2012-12-07 152 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

你的實現是非常相似的BooleanLatch,在AbstractQueuedSynchronizer的Java的文檔提供了protected try*()方法你鎖定的政策,我想你需要調用同步。當你打開大門時,釋放共享(1) – hoaz

回答

2

它看起來像setState()只改變狀態,但不通知阻止的線程有關更改。

因此,你應該使用獲取/釋放方法代替:

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

所以,AbstractQueuedSynchronizer整體工作流程看起來像如下:

  • 客戶端調用public獲取/釋放方法

  • 這些方法安排所有同步功能並將實際鎖定策略委託給protected try*()種方法

  • 您定義使用getState()/setState()/compareAndSetState()