簡體   English   中英

Java:等待布爾值變為真實

[英]Java: Wait a boolean to become true

我實現了一個任務,當前線程將等到之前的工作完成。

碼:

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

另一個線程將isPreviousWorkDone設置為true,然后我們可以運行doSomething() 但是我認為我的代碼很糟糕:

  1. 我們每100ms檢查一次,這可能會花費一些CPU資源。
  2. 很難添加等待超時。 (如果isPreviousWorkDone從未變為真怎么辦?)

那么,如何正確執行這樣的等待呢?

請改用CountDownLatch 一個java.util.concurrent.CountDownLatch允許一個或多個線程等待某些操作完成。

CountDownLatch用給定的計數初始化。 需要等待某種條件/操作(計數達到零)的線程,調用await()方法之一。 通過調用countdown()方法,計數從完成某些操作的線程中減少。 然后,所有等待線程繼續執行。

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

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

定義Worker 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
 }

(有關此主題的更多信息,請參閱Doug Lea的“ Java並行編程(第二版)”(Addison-Wesley,2000年)中的3.2.3節,或Joshua Bloch的“有效的Java編程語言指南”(Addison-衛斯理,2001)。

您想要實現的是顯示器的工作。 使用充當監視器的對象,您可以在需要時使線程等待/喚醒。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM