2013-09-26 1 views
31

У меня есть поток, который ждать логическое значение, чтобы изменить так:Подождите, пока логическое значение не изменяет его состояние

while(!value) 
{ 
    Thread.sleep(1000) 
} 
// Do some work after change of the value 

Это не мой Предпочитаемый способ сделать это, причиной массового потребления процессора.

Есть ли способ заблокировать Thread, пока значение boolean не изменится?

ответ

58

Это не мой предпочтительный способ сделать это, вызывая массовое потребление ЦП.

Если это фактически ваш рабочий код, то просто держите его таким. Проверка логического значения один раз в секунду вызывает отсутствие измеримой нагрузки ЦП. Никак нет.

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

private volatile boolean value; 

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

+4

+1 для предложения «volatile» ... – TheLostMind

7

Как насчет wait-notify

private Boolean bool = true; 
private final Object lock = new Object(); 

private Boolean getChange(){ 
    synchronized(lock){ 
    while (bool) { 
     bool.wait(); 
    } 
    } 
    return bool; 
} 
public void setChange(){ 
    synchronized(lock){ 
     bool = false; 
     bool.notify(); 
    } 
} 
+7

'bool' - изменяемое поле, вы не можете синхронизировать его. – axtavt

+0

umm ... это фактически пункт Point @axtavt. –

+0

И теперь вы синхронизируетесь в не конечном поле. В 'setChange' вы сначала измените его, а затем уведомите новый экземпляр' false'. Результат: поток, ожидающий более раннего экземпляра 'true', никогда не получает уведомления. Еще один прекрасный пример того, почему * избежать * всего этого механизма. –

34

Вам нужен механизм, который позволяет избежать занятости-ожидания. Старый wait/notify механизм таит в себе подводные камни, так предпочитают что-то из java.util.concurrent библиотеки, например CountDownLatch:

public final CountDownLatch latch = new CountDownLatch(1); 

public void run() { 
    latch.await(); 
    ... 
} 

А на другой стороне вызова

yourRunnableObj.latch.countDown(); 

Однако, начиная нить не делать ничего, кроме ждать, пока это будет необходимо, все равно не лучший способ. Вы также можете использовать ExecutorService, на который вы отправляете в качестве задачи работу, которая должна выполняться при выполнении условия.

+0

Это помогает мне проверить библиотеку кварца внутри JUnit. Quartz выполняет свои задания в черном ящике с собственным пулом потоков. Я могу сигнализировать JUnit, чтобы дождаться завершения задания кварца, используя точный шаблон, указанный в java-документе. –

+0

Могу ли я предложить 'Java.util.concurrent.BlockingQueue' и его различные реализации? Методы 'take()' и 'offer()' являются отличным отправным местом для синхронизации. – Groostav

1

Я предпочитаю использовать механизм mutex в таких случаях, но если вы действительно хотите использовать логическое значение, тогда вы должны объявить его изменчивым (чтобы обеспечить видимость изменения в потоках) и просто запустить цикл бездействия с помощью этого логического в качестве условия:

//.....some class 

volatile boolean someBoolean; 

Thread someThread = new Thread() { 

    @Override 
    public void run() { 
     //some actions 
     while (!someBoolean); //wait for condition 
     //some actions 
    } 

}; 
+15

Не будет ли это пережевывать процессор? –

2

Возможно, этот вопрос должен решить вашу проблему. Обратите внимание, что каждый раз, когда вы делаете изменения, вы вызываете метод change(), который освобождает ожидание.

Integer any = new Integer(0); 

public synchronized boolean waitTillChange() { 
    any.wait(); 
    return true; 
} 

public synchronized void change() { 
    any.notify(); 
} 
+2

Целое слово неизменное, вы не можете изменить его значение – Andrejs

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