2012-12-07 11 views
5

Ich habe eine einfache Klasse geschrieben, die AbstractQueuedSynchronizer verwendet. Ich habe eine Klasse geschrieben, die ein "Tor" darstellt, das übergeben werden kann, wenn es offen ist, oder es blockiert, wenn es geschlossen wird. Hier ist der Code:AbstractQueuedSynchronizer.acquireShared wartet unendlich, auch wenn sich die Wartebedingung geändert hat

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); 
    } 

}; 

Leider, wenn ein Thread-Blöcke auf Pass Methode, weil Tor geschlossen ist und ein anderer Thread öffnet das Tor in Zwischenzeit die blockierte man nicht unterbrochen bekommt - Es blockiert unendlich. Hier ist ein Test, es zeigt:

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(); 
    } 
} 

Bitte helfen Sie, was soll ich das Tor Gang Thread die Sperre erfolgreich erwerben machen ändern.

+0

Ihre Implementierung ist sehr ähnlich zu BooleanLatch, sofern in AbstractQueuedSynchronizer Java-Doc mit in protected try*() Methoden definieren, ich nehme an, Sie müssen synchron nennen. releaseShared (1) wenn du Tore öffnest – hoaz

Antwort

2

Es sieht aus wie setState() ändert nur den Zustand, aber nicht blockiert blockiert Threads über die Änderung.

Daher sollten Sie acquire/Freigabeverfahren statt:

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

So sieht gesamten Workflow von AbstractQueuedSynchronizer wie folgt:

  • Clients rufen public acquire/Freigabeverfahren

  • Diese Methoden ordnen alle Synchronisierungsfunktionen an und delegieren die aktuelle Sperrrichtlinie an protected try*() Methoden

  • Sie Ihre Sperrpolitik getState()/setState()/compareAndSetState()

Verwandte Themen