자바 에서 읽 기와 쓰기 자물쇠 의 디자인 및 구현
8620 단어 자바
한편,RRW 는 여러 개의 읽 기 스 레 드 를 동시에 방문 할 수 있 지만 스 레 드 와 읽 기 스 레 드,쓰기 스 레 드 와 쓰기 스 레 드 를 동시에 방문 할 수 없습니다.읽 기와 쓰기 자물쇠 내부 에 두 개의 자 물 쇠 를 유지 하고 있 습 니 다.하 나 는 읽 기 동작 에 사용 되 는 ReadLock 이 고 하 나 는 쓰기 동작 에 사용 되 는 WriteLock 입 니 다.
읽 기와 쓰기 자 물 쇠 는 다음 과 같은 세 가지 기본 원칙 을 준수 한다.
읽 기와 쓰기 자 물 쇠 는 어떻게 실현 합 니까?
RRW 도 AQS 를 기반 으로 이 루어 졌 습 니 다.사용자 정의 동기 화 장치(AQS 계승)는 동기 화 상태 state 에서 여러 개의 읽 기 스 레 드 와 쓰기 스 레 드 상 태 를 유지 해 야 합 니 다.RRW 의 방법 은 높낮이 를 사용 하여 하나의 성형 제어 두 가지 상 태 를 실현 하 는 것 이다.하 나 는 int 가 4 개의 바이트,하 나 는 8 개의 바이트 를 차지한다.그래서 고 16 위 는 읽 고,저 16 위 는 쓴다.
abstract static class Sync extends AbstractQueuedSynchronizer {
static final int SHARED_SHIFT = 16;
// 10000000000000000(65536)
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
// 65535
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
//1111111111111111
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
// ( ) , 16
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
// ( )
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
}
읽 기 자물쇠 가 져 오기
스 레 드 가 읽 기 자 물 쇠 를 가 져 올 때 먼저 동기 상태 가 16 비트 가 낮은 것 을 판단 하고,쓰기 자물쇠 가 존재 하면 자 물 쇠 를 가 져 오 는 데 실패 하고,CLH 대기 열 에 들 어가 서 막 아야 하 는 지,반대로 현재 스 레 드 가 막 혀 야 하 는 지 판단 하고,막 히 지 않 으 면 CAS 동기 화 상 태 를 시도 하여 동기 자 물 쇠 를 읽 기 상태 로 성공 적 으로 업데이트 합 니 다.
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
// ,
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
//
int r = sharedCount(c);
// readerShouldBlock() true CLH
// CAS
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
// readLock
return 1;
}
//
return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {
//
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0) {
// , CLH
if (getExclusiveOwnerThread() != current)
return -1;
}
// reader
else if (readerShouldBlock()) {
// Make sure we're not acquiring read lock reentrantly
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
// , 。 CLH
if (rh.count == 0)
return -1;
}
}
//
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// CAS
if (compareAndSetState(c, c + SHARED_UNIT)) {
// readLock
return 1;
}
}
}
SHARED_UNIT
의 값 은 65536 이다.즉,읽 기 자 물 쇠 를 처음 얻 은 후에 state 의 값 은 65536 이 되 었 다.공정 한 잠 금 실현 에서 CLH 대기 열 에 줄 을 서 는 스 레 드 가 있 으 면readerShouldBlock()
방법 은 true 로 돌아 갑 니 다.불공평 한 잠 금 의 실현 은 CLH 대기 열 에 잠 금 을 가 져 오 기 를 기다 리 는 스 레 드 가 존재 하면 true 로 돌아 갑 니 다.또한 주의해 야 할 것 은 읽 기 자 물 쇠 를 가 져 올 때 현재 스 레 드 에 쓰기 자 물 쇠 를 가지 고 있다 면 읽 기 자 물 쇠 를 성공 적 으로 가 져 올 수 있 습 니 다.뒤에 자물쇠 의 강등 이 언급 될 것 입 니 다.만약 당신 이 그곳 의 코드 에 대해 의문 이 있다 면,여기 서 자 물 쇠 를 신청 하 는 코드 를 돌아 볼 수 있 습 니 다.
읽 기 잠 금 해제
protected final boolean tryReleaseShared(int unused) {
for (;;) {
int c = getState();
// 65536
int nextc = c - SHARED_UNIT;
// state 0
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
자 물 쇠 를 풀 때 state 의 값 은 65536 을 빼 야 합 니 다.읽 기 자 물 쇠 를 처음 가 져 온 후에 state 값 은 65536 이 되 었 기 때 문 입 니 다.
모든 스 레 드 가 읽 기 자 물 쇠 를 풀 때
state==0
에 만 자 물 쇠 를 풀 었 습 니 다.예 를 들 어 100 개의 스 레 드 가 읽 기 자 물 쇠 를 가 져 왔 고 마지막 스 레 드 가 실행tryReleaseShared
방법 을 실행 할 때 만 자 물 쇠 를 풀 었 습 니 다.이때 CLH 대기 열 에 있 는 줄 서기 스 레 드 를 깨 울 것 입 니 다.쓰기 잠 금 가 져 오기
하나의 스 레 드 가 자 물 쇠 를 가 져 오 려 고 시도 할 때 동기 상태 state 가 0 인지 먼저 판단 합 니 다.state 가 0 이면 다른 스 레 드 가 잠 금 을 가 져 오지 않 았 음 을 설명 합 니 다.state 가 0 이 아니라면 다른 스 레 드 가 자 물 쇠 를 가 져 왔 다 는 뜻 입 니 다.
이때 state 의 낮은 16 비트(w)가 0 인지 여 부 를 판단 합 니 다.w 가 0 이면 다른 스 레 드 가 읽 기 자 물 쇠 를 가 져 왔 음 을 표시 합 니 다.이때 CLH 대기 열 에 들 어가 서 차단 대기 합 니 다.
만약 w 가 0 이 아니라면 다른 스 레 드 가 쓰기 자 물 쇠 를 가 져 왔 다 는 것 을 설명 합 니 다.이 때 는 쓰기 자 물 쇠 를 가 져 온 것 이 현재 스 레 드 인지 아 닌 지 판단 해 야 합 니 다.그렇지 않 으 면 CLH 대기 열 에 들 어가 서 차단 하고 기 다 립 니 다.만약 에 쓰기 자 물 쇠 를 가 져 온 것 이 현재 스 레 드 라면 현재 스 레 드 가 쓰기 자 물 쇠 를 가 져 온 것 이 최대 횟수 를 초과 하 였 는 지 판단 하고 초과 하면 이상반대로 동기 화 상 태 를 업데이트 합 니 다.
//
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
// state 0
if (c != 0) {
//
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 65535
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//
setState(c + acquires);
return true;
}
// writerShouldBlock() false
// CAS state
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
// CAS ,
setExclusiveOwnerThread(current);
return true;
}
공정 한 잠 금 실현 중 CLH 대기 열 에 줄 을 서 는 스 레 드 가 존재 하면
writerShouldBlock()
방법 은 true 로 되 돌아 갑 니 다.이때 잠 금 을 쓰 는 스 레 드 를 가 져 오 는 것 이 막 힙 니 다.자 물 쇠 를 풀다
자 물 쇠 를 풀 어 주 는 논 리 는 비교적 간단 하 다.
protected final boolean tryRelease(int releases) {
//
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
//
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
자물쇠 의 업그레이드?
//
readLock.lock();
try {
v = map.get(key);
if(v == null) {
writeLock.lock();
try {
if(map.get(key) != null) {
return map.get(key);
}
// ,
} finally {
writeLock.unlock();
}
}
} finally {
readLock.unlock();
}
위 에서 캐 시 데이터(이것 도 RRW 의 응용 장면)를 가 져 오 는 코드 에 대해 먼저 읽 기 자 물 쇠 를 가 져 온 다음 에 자 물 쇠 를 쓰 는 것 으로 업그레이드 하 는 행 위 를 자물쇠 의 업그레이드 라 고 합 니 다.안 타 깝 게 도 RRW 는 지원 하지 않 습 니 다.그러면 자 물 쇠 를 영구적 으로 기다 리 게 되 고 결국은 스 레 드 가 영구적 으로 막 힐 수 있 습 니 다.그래서 자물쇠 의 업 그 레이 드 는 허용 되 지 않 습 니 다.
자물쇠 의 강등
자물쇠 의 업 그 레이 드 는 허용 되 지 않 지만 자물쇠 의 강등 은 가능 하 다.
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReadLock readLock = lock.readLock();
WriteLock writeLock = lock.writeLock();
Map dataMap = new HashMap();
public void processCacheData() {
readLock.lock();
if(!cacheValid()) {
// ,
readLock.unlock();
writeLock.lock();
try {
if(!cacheValid()) {
dataMap.put("key", "think123");
}
//
readLock.lock();
} finally {
writeLock.unlock();
}
}
try {
//
System.out.println(dataMap);
} finally {
readLock.unlock();
}
}
public boolean cacheValid() {
return !dataMap.isEmpty();
}
RRW 가 주의해 야 할 문제
추천
이전에 AQS 의 실현,ReentrantLock 의 실현 이 라 고 쓴 적 이 있 습 니 다.아래 의 글 을 참고 하 시기 바 랍 니 다.
나 를 지 켜 봐,길 을 잃 지 않 아.
형님,저 에 게 좋아요 와 관심 을 주 시 겠 어 요?
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.