0

Я пытаюсь выполнить следующий код:Atomic Логическое использование в многопоточном приложении

В моем конструкторе я инициализировать свою атомную булево:

Atomic Boolean isChannelActive = new AtomicBoolean(false); 

В моем методе записи я проверить это логическое и ждать:

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

Но проблема эта атомная булева может быть установлена ​​из другого потока в то время, когда программа находится на:

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

Таким образом, в этом случае мое атомное булево значение будет истинным, и я пропущу событие notifyAll() и будет ждать навсегда из-за контекстного переключателя.

Как я могу предотвратить эту проблему?

Я знаю, что синхронизированные блоки могут быть вариантом, но я ищу более элегантный вариант для этого случая.

+0

Если вы вызываете 'wait()' вы уже ** в ** блоке 'synchronized'. – Kayaman

+0

Может ли [Условия] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html) быть альтернативой? – Fildor

+0

Я также смотрю на механизм CountdownLatch и также отлично работает. Такую же проблему можно решить с помощью [CountdownLatches] (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html) –

ответ

2

Вы не должны смешивать механизмы синхронизации с разных уровней.

  1. wait/notify - это архаичная система, вам не нужно использовать больше. Все, что вы можете сделать с помощью wait/notify, может быть сделано с помощью synchronized или Lock s.

  2. synchronized - это позволяет синхронизировать код, чтобы секции, которые нуждались в эксклюзивном доступе, не мешали друг другу.

  3. Lock s - Существуют различные типы замков, которые обычно могут обрабатывать практически любое управление доступом, которое вам нравится.

  4. Blocking... - Это более современный подход - он использует структуры данных для обеспечения безопасного доступа, а не для синхронизации в коде.

  5. Есть еще множество функций, таких как Phaser и Semaphore, которые могут использоваться для достижения некоторых из наиболее распространенных механизмов.

Вы attemptin использовать atomics и wait/notify одновременно. Это не сработает без трудностей.

Возможно, вам просто нужен Lock.

Lock channelActive = new ReentrantLock(); 

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

} 
2

Если вы звоните wait(), вы уже являетесь в a synchronized блок. Ваш сценарий является гипотетическим, так как оба потока, которые вызывают wait() и notifyAll(), должны получить тот же монитор объекта.

Поэтому невозможно, чтобы в месте, где вы претендуете, есть переключатель контекста [1]. Также нет преимуществ при использовании AtomicBoolean здесь (по крайней мере, исходя из того, что вы показали), простой volatile boolean будет работать так же хорошо.

[1] Невозможно, вы могли бы написать код, поэтому проверка состояния находится за пределами синхронизированного блока, но это было бы намеренно писать сломанный параллельный код.

Смежные вопросы