4

:ReentrantReadAndWriteLock에서 writeLock.lock() 전에 readLock()을 잠금 해제해야하는 이유는 무엇입니까? <a href="http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html" rel="nofollow">ReentrantReadAndWriteLock class javadoc</a>에서

우리가 코멘트에 작성된 쓰기 잠금을 획득하기 전에 읽기 잠금을 해제해야하는 이유
void processCachedData() { 
    rwl.readLock().lock(); 
    if (!cacheValid) { 
    // Must release read lock before acquiring write lock 
5: rwl.readLock().unlock(); 
6: rwl.writeLock().lock(); 
    // Recheck state because another thread might have acquired 
    // write lock and changed state before we did. 
    if (!cacheValid) { 
     data = ... 
     cacheValid = true; 
    } 
    // Downgrade by acquiring read lock before releasing write lock 
14: rwl.readLock().lock(); 
15: rwl.writeLock().unlock(); // Unlock write, still hold read 
    } 

    use(data); 
    rwl.readLock().unlock(); 
} 

? 현재 스레드가 읽기 잠금을 보유하고 있으면 현재 스레드가 읽기 잠금을 보유하고 있는지 여부에 관계없이 다른 스레드가 더 이상 읽지 않을 때 쓰기 잠금을 획득 할 수 있어야합니다. 이것은 내가 기대하는 행동입니다. 결국 4 번과 5 번 라인에서 업그레이드를 잠그고 14 번과 15 번 라인에서 다운 그레이드하면 ReentrantReadAndWriteLock 클래스에서 내부적으로 완료 될 것으로 예상됩니다. 왜 그럴 수 없습니까?

은 즉, 나는 코드는 다음과 같이 잘 작동하는 기대 :

void processCachedData() { 
    rwl.readLock().lock(); 
    if (!cacheValid) { 
    // The readlock is upgraded to writeLock when other threads 
    // release their readlocks. 
    rwl.writeLock().lock(); 
    // no need to recheck: other threads can't have acquired 
    // the write lock since this thread still holds also the readLock!!! 
    if (!cacheValid) { 
     data = ... 
     cacheValid = true; 
    } 
    // Downgrade by acquiring read lock before releasing write lock 
    rwl.writeLock().unlock(); // Unlock write, still hold read 
    } 

    use(data); 
    rwl.readLock().unlock(); 
} 

이가, 더 잠금 처리 할 수있는보다 안전한 방법으로 많이하지 않습니다 보인다?

누군가가 왜이 이상한 구현을 설명 할 수 있습니까? 감사.

+0

두 개 이상의 스레드가 동시에이 작업을 수행하려고하면 어떤 일이 발생할지 고려해야합니다. – EJP

답변

10

, 그것은 교착 상태가 발생할 수 있습니다.

  1. 스레드 A : : 다음과 같은 순서를 고려 취득은
  2. 스레드 B를 잠글 읽기 : 읽기 잠금을 획득 (두 스레드가 현재 읽기 잠금을 공유합니다).
  3. 스레드 A가 : 쓰기 잠금 (스레드 B와 같은 블록 읽기 보유 잠금)
  4. 스레드 B를 취득하려고 :

는 지금이 쓰기 잠금 (블록 스레드 A를 읽을 보유 잠금)을 취득하려고 이중 자물쇠. 스레드 A 나 B는 진행할 수 없으며 읽기 잠금을 해제하지도 않습니다.

+0

동기화 된 교착 상태 응답 (말장난/모순 대상 : -D) –

+0

감사합니다. 말된다. –

+1

일부 판독기/기록기 잠금은 스레드가 "업그레이드 가능한 판독기"잠금을 획득 할 수있게합니다. 그러한 락을 보관 유지하는 다른 thread가없는 경우, 읽기 락을 취득하려고했을 경우와 같이 락을 취득하려고하면 (자) 성공합니다. 다만, 다른 thread가 이미 그러한 락을 보관 유지하고있는 경우, 그 락을 취득하는 2 번째의 시도는, 최초의 thread가 락을 해제하는지, 또는 업그레이드 할 수 없게 「강등」할 때까지 블록됩니다. 이러한 잠금은 쓰기 전용 잠금으로 업그레이드하기 전에 잠긴 리소스에 대한 모든 관찰을 유효하게 유지한다는 장점이 있습니다. – supercat

3

Reentrancy를 사용하면 쓰기 잠금을 획득 한 다음 읽기 잠금을 해제하고 쓰기 잠금을 해제하여 쓰기 잠금에서 읽기 잠금으로 다운 그레이드 할 수 있습니다. 그러나 읽기 잠금에서 쓰기 잠금으로 업그레이드하는 것은 불가능합니다 (교착 상태가 발생 함).

출처 : 두 스레드가 동시에 그것을하려고하면 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html 쓰기 잠금에 읽기 잠금을 업그레이드의 문제가

+0

이것은 또한 문서에 기록되어 있습니다. 제가 포즈를 취하는 질문은 * 왜 *입니까? 만약 내가 그 일을 구현했다면, 나는 readlock을 가지고 있으면 쓰기 획득을 방해하지 않는다고 생각할 것이다. –

5

Javadoc은 읽기 잠금을 쓰기 잠금으로 업그레이드하는 것은 명시 적으로 불가능하다고 설명합니다. 이유는입니다. 교착 상태가 발생할 수 있기 때문입니다.

  • 스레드 1 취득 스레드 2 취득은 1

두 스레드가 작성

  • 스레드 2 쓰기 잠금을 업그레이드하도록 요청 잠금을 업그레이드 요청
  • 스레드 잠금을 읽어
  • 잠금을 읽어 지금 서로 기다리고있어. 영원히.