0

Ich versuche, den folgenden Code auszuführen:Atomic Boolean Verwendung in Multithread-Anwendung

In meinem Konstruktor i initialisieren meine Atom boolean:

Atomic Boolean isChannelActive = new AtomicBoolean(false); 

In meiner Schreibmethode ich diese boolean überprüfen und warten:

public ChannelFuture write(ByteBuf msgBuf) { 
if (!isChannelActive.get()) { 
    try { 
    wait(); 
    } catch (InterruptedException ex) { 
    logger.Error("Waiting interrupted", ex); 
    } 
} 

Aber das Problem ist, das Atom boolean kann zu der Zeit von anderem Thread eingestellt wird, wenn Programm eingeschaltet ist:

if (!isChannelActive.get()) { 
    try{ --- Right on here and program made a context switch at this time. 
    wait() 

Also in diesem Szenario wird meine atomische Boolean wahr sein und ich vermisse das notifyAll() Ereignis und wird für immer auf den Kontextwechsel warten.

Wie kann ich dieses Problem verhindern?

Ich weiß, dass synchronisierte Blöcke die Option sein können, aber ich suche nach eleganteren Option für diesen Fall.

+0

Wenn Sie 'wait()' nennen, sind Sie bereits ** in ** einem 'synchronisierten' Block. – Kayaman

+0

Könnte [Bedingungen] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html) eine Alternative sein? – Fildor

+0

Ich habe auch einen anderen Blick auf CountdownLatch Mechanismus und funktioniert auch gut. Das gleiche Problem kann mit [CountdownLatches] (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html) erreicht werden. –

Antwort

2

Sie sollten keine Synchronisationsmechanismen aus verschiedenen Ebenen mischen.

  1. wait/notify - Dies ist ein archaisches System, das Sie brauchen nicht mehr zu verwenden. Alles was Sie können mit wait/notify kann mit synchronized oder Lock s getan werden.

  2. synchronized - Damit können Sie Code synchronisieren, so dass Abschnitte, die exklusiven Zugriff benötigen, sich nicht gegenseitig stören.

  3. Lock s - Es gibt verschiedene Arten von Schlössern, die im Allgemeinen fast jede Zugangskontrolle, die Sie mögen, handhaben können.

  4. Blocking... - Dies ist der modernere Ansatz - es verwendet Datenstrukturen, um einen sicheren Zugriff zu gewährleisten, anstatt die Synchronisierung in den Code zu stellen.

  5. Es gibt weitere Sätze von Funktionen wie Phaser und Semaphore, die verwendet werden können, um einige der gebräuchlicheren Mechanismen zu erreichen.

Du attemptin atomics und wait/notify zur gleichen Zeit zu nutzen. Dies wird nicht ohne Schwierigkeiten funktionieren.

Sie brauchen wahrscheinlich nur eine Lock.

Lock channelActive = new ReentrantLock(); 

public void test() { 
    channelActive.lock(); 
    try { 
     // Do your exclusive stuff here. 
    } finally { 
     channelActive.unlock(); 
    } 

} 
2

Wenn Sie wait() anrufen, sind Sie bereits in ein synchronized Block. Ihr Szenario ist ein hypothetisches Szenario, da beide Threads, die wait() und notifyAll() aufrufen, denselben Objektmonitor abgerufen haben müssen.

Daher ist es unmöglich, dass es einen Kontextwechsel an der Stelle gibt, die Sie beanspruchen [1]. Es gibt auch keinen Vorteil bei der Verwendung eines AtomicBoolean hier (zumindest basierend auf dem, was Sie gezeigt haben), eine einfache volatile boolean würde genauso gut funktionieren.

[1] Nicht unmöglich, könnten Sie den Code schreiben, so dass die Bedingungsprüfung außerhalb eines synchronisierten Blocks ist, aber das würde absichtlich gebrochenen gleichzeitigen Code schreiben.