2016-04-11 2 views
1

Я выполнил задачу, текущая нить которой будет ждать до тех пор, пока не будет выполнена предыдущая работа.Java: Подождите, когда значение boolean станет истинным

Код:

while (!taskContext.isPreviousWorkDone()) { 
     try { 
      Thread.sleep(100); 
     } catch (InterruptedException e) { 
      LOGGER.error("Wait failed", e); 
     } 
    } 
    doSomething(); 

Другой поток будет установлен isPreviousWorkDone к истинным, а затем мы можем запустить doSomething(). Но я думаю, что мой код плох:

  1. мы проверяем, что каждый 100ms, и это может стоить некоторый ресурс ЦП.
  2. Трудно добавить время ожидания ожидания. (Что делать, если isPreviousWorkDone никогда не станет реальностью?)

Итак, как реализовать такое ожидание должным образом?

+0

Вы можете построить тайм-аут – Stultuske

+0

Проверьте этот вопрос: https://stackoverflow.com/questions/1036754/разница между ожиданиями и ожиданиями ждут вместо сна и работают с сигналами :) – Yuri

+1

Вы можете использовать 'Object # wait' или' ReentrantLock' и 'Condition' – MadProgrammer

ответ

2

Используйте CountDownLatch вместо этого. A java.util.concurrent.CountDownLatch позволяет одному или нескольким потокам ждать выполнения некоторых операций.

CountDownLatch инициализируется данным счетом. Темы, которые должны ждать некоторого условия/операции (для того, чтобы число достигло нуля), вызовите один из методов wait(). Счет уменьшается из потока, который завершил некоторую операцию, вызвав метод обратного отсчета(). Затем все ожидающие потоки продолжают выполнение.

Пример

// create latch with count of one (1) 
CountDownLatch latch = new CountDownLatch(1); 

// create instances of classes that implement Runnable 
Waiter waiter = new Waiter(latch); 
Worker worker = new Worker(latch); 

// start threads 
new Thread(waiter).start(); 
new Thread(worker).start(); 

Определить Официант Runnable (ожидает в течение некоторого завершения операции)

public class Waiter implements Runnable{ 
    CountDownLatch latch = null; 

    public Waiter(CountDownLatch latch) { 
     this.latch = latch; 
    } 

    public void run() { 
     try { 
      // wait for the latch to be released 
      latch.await(); 
     } catch (InterruptedException e) { 
      // set interupt flag 
      Thread.currentThread().interrupt(); 
      // log interrupt 
      System.out.println("Interrupted"); 
     } 
     System.out.println("Unblocked"); 

     doSomething(); 
    } 
} 

Определить работник Runnable (выполняет некоторую операцию)

public class Worker implements Runnable { 
    CountDownLatch latch = null; 

    public Worker(CountDownLatch latch) { 
     this.latch = latch; 
    } 

    public void run() { 
     // do some job 

     // when ready release latch 
     latch.countDown(); 

     System.out.println("Latch Released"); 
    } 
} 

Избегайте

Используя старый поживем уведомит Java API. Причина в том, что поддельные пробуждения. Это ваша нить просыпается без фактического уведомления, поэтому вам нужно проверить, удовлетворено ли ваше состояние или продолжать ждать.

Ложные пробуждений из javadocs

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

synchronized (obj) { 
    while (<condition does not hold>) 
     obj.wait(timeout); 
    ... // Perform action appropriate to condition 
} 

(Для получения дополнительной информации по этой теме, смотрите Раздел 3.2.3 в «Параллельное программирование в Java (Second Edition)» Дага Ли (Addison -Wesley, 2000) или Пункт 50 в «Руководстве по эффективному языковому программированию на Java» Джошуа Блоха (Addison-Wesley, 2001).

0

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

synchronized(lock) 
{ 
    while(!taskContext.isPreviousWorkDone()) 
    { 
     try 
     { 
      // Object lock has to be accessible both by waiting thread and any 
      // other thread that marks the previous work as done 
      lock.wait(); 
     } 
    } 
} 

Теперь, где бы вы обновить контекст задачи, вы должны разбудить ожидающую тему

// Method where you update taskContext 
public synchronized void setWorkAsDone() throws Exception 
{ 
    // ... 
    _isPreviousWorkDone = true; 
    notifyAll(); 
    // ... 
} 
Смежные вопросы