2012-12-07 3 views
5

AbstractQueuedSynchronizer를 사용하는 간단한 클래스를 작성했습니다. "게이트"를 나타내는 클래스를 작성했습니다.이 클래스는 열려 있으면 통과 할 수 있고 닫히면 블로킹합니다. 여기에 코드입니다 : 패스 방법에 스레드 블록이 게이트를 폐쇄하고 다른 스레드가 그 동안 문을 열고 있기 때문에 경우AbstractQueuedSynchronizer.acquireShared는 대기 상태가 변경되었다하더라도 무한히 대기합니다.

public class GateBlocking { 

    final class Sync extends AbstractQueuedSynchronizer { 
    public Sync() { 
     setState(0); 
    } 

    @Override 
    protected int tryAcquireShared(int ignored) { 
     return getState() == 1 ? 1 : -1; 
    } 

    public void reset(int newState) { 
     setState(newState); 
    } 
    }; 

    private Sync sync = new Sync(); 

    public void open() { 
    sync.reset(1); 
    } 

    public void close() { 
    sync.reset(0); 
    } 

public void pass() throws InterruptedException { 
    sync.acquireShared(1); 
    } 

}; 

불행하게도, 차단 된 사람이 중단되지 않습니다 - 그것은 블록 무한.

public class GateBlockingTest { 

    @Test 
    public void parallelPassClosedAndOpenGate() throws Exception{ 
     final GateBlocking g = new GateBlocking(); 
     Thread t = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        Thread.sleep(2000); 
        g.open(); 
       } catch (InterruptedException e) { 
       } 
      } 
     }); 


     t.start(); 
     g.pass(); 
    } 
} 

이 도와주세요, 내가 게이트 통과 스레드가 성공적으로 잠금을 획득하도록 변경해야하는지 : 은 여기를 표시하는 테스트입니다.

+0

귀하의 구현이 AbstractQueuedSynchronizer의 자바 문서에서 제공 BooleanLatch,과 매우 유사하여 protected try*() 방법에 잠금 정책을 정의, 당신이 동기화를 호출 할 필요가 가정합니다. 게이트를 열면 releaseShared (1) – hoaz

답변

2

마치 setState()은 상태 만 변경하지만 차단 된 스레드에 변경 사항을 알리지 않습니다.

  • 클라이언트는 public 취득/해제 방법

  • 를 호출하는 대신

    따라서 사용한다 취득/해제 방법 : 다음과 같은

    @Override 
    protected boolean tryReleaseShared(int ignored) { 
        setState(1); 
        return true; 
    } 
    ... 
    public void open() { 
        sync.releaseShared(1); 
    } 
    

    그래서, AbstractQueuedSynchronizer의 전반적인 흐름 보인다 이 방법은 모든 동기화 기능을 조정하고 실제 잠금 정책을에 위임합니다.방법

  • 당신은 getState()/setState()/compareAndSetState()