2011-03-07 221 views
5

我經常需要有一個線程等待另一個線程的結果。似乎在java.util.concurrent中應該有一些支持,但我找不到它。如何讓一個java線程等待另一個線程的結果?

Exchanger非常接近我所說的,但它是雙向的。我只想讓線程A在線程B上等待,而不是彼此等待。

是的,我知道我可以使用CountDownLatch或Semaphore或Thread.wait(),然後自己管理計算結果,但似乎我必須在某處丟失便利類。

我錯過了什麼?

UPDATE

// An Example which works using Exchanger 
// but you would think there would be uni-directional solution 
protected Exchanger<Integer> exchanger = new Exchanger<Integer>(); 

public void threadA() { 
    // perform some computations 
    int result = ...; 

    exchanger.exchange(result); 
} 


public void threadB() { 

    // retrieve the result of threadA 
    int resultOfA = exchanger.exchange(null); 
} 
+0

你可以鎖定資源嗎?它會阻塞調用線程,直到第一個解鎖資源。您可以使用它做很多事情:http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html – 2011-03-07 20:22:28

+0

Exchanger的另一個問題是它只適用於**線程對**。使用交換器,不可能有多個線程等待要設置的值。 – sjlee 2011-03-08 05:57:23

回答

5

到目前爲止,好像BlockingQueue可能是我找到的最佳解決方案。

例如。

BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(1); 

的等待線程將調用queue.take()等待結果,而生產隊列會調用queue.add()提交結果。

7

您是否在尋找Future<T>?這是(通常)已經提交給工作隊列的任務的正常表示,但可能尚未完成。你可以找到它的完成狀態,阻止它完成,等等。

看看ExecutorService爲正常的獲得期貨的方式。請注意,這關注於獲取個人任務的結果,而不是等待線程完成。單線程可能會在其生命週期內完成許多任務,當然,這就是線程池的全部要點。

+0

Future的問題是我需要使用CountdownLatch或其他一些同步機制來管理結果何時可用。它最終會比使用Exchanger更多的代碼(我相信) – emmby 2011-03-07 16:59:38

+1

@emmby:爲什麼你需要這樣做?如果你很高興阻止,只需從消費線程調用'future.get()'。如果你想添加超時。目前還不清楚爲什麼這對你不起作用......唯一的問題是,如果產生價值的線程仍然在繼續做其他事情......你還沒有把大局看得很清楚。 – 2011-03-07 17:03:13

+0

嗨,喬恩,我用一個希望證明我在說什麼的例子更新了這個問題。 – emmby 2011-03-07 17:14:56

0

使用Thread.join()時有什麼不便?

+0

我認爲他想等待一個線程修改一個值,而不是一個線程完成他的工作,沒有? – reef 2011-03-07 16:38:59

+0

好的,謝謝澄清 – cadrian 2011-03-08 09:09:06

0

我最近有同樣的問題,嘗試使用Future然後CountdownLatch,但在交換器上定居。它們應該允許兩個線程交換數據,但沒有理由爲什麼其中一個線程不能傳遞null。

最後我認爲這是最乾淨的解決方案,但它可能取決於你想要達到的目標。

+0

這是完全一樣的情況,我發現我很高興聽到這不僅僅是我現在我正在試圖決定BlockingQueue還是Exchanger(或者別的什麼)是最乾淨的範例 – emmby 2011-03-07 16:44:06

0

您可能會對此使用java.util.concurrent.CountDownLatch。

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html

例子:

CountDownLatch latch = new CountDownLatch(1); 

// thread one 
// do some work 
latch.countDown(); 

// thread two 
latch.await(); 
+0

我懷疑OP是否已經意識到:「是的,我知道我可以使用CountDownLatch或...「 – 2011-03-07 17:17:23

+0

'是的,我知道我可以使用CountDownLatch或Semaphore或Thread.wait(),然後自己管理計算結果,但似乎我必須缺少便利類' – 2011-03-07 17:17:50

4

的JDK不提供一個方便的類,它提供你正在尋找具體的功能。但是,編寫一個小實用程序類來做到這一點實際上相當容易。

你提到了CountDownLatch和你的喜好,但我仍然建議看看它。(如果你將一個「值同步」),你可以建立一個小工具類很容易地:

public class OneShotValueSynchronizer<T> { 
    private volatile T value; 
    private final CountDownLatch set = new CountDownLatch(1); 

    public T get() throws InterruptedException { 
     set.await(); 
     return value; 
    } 

    public synchronized void set(T value) { 
     if (set.getCount() > 0) { 
      this.value = value; 
      set.countDown(); 
     } 
    } 

    // more methods if needed 
} 
+0

這就是我正在尋找的那種課程,謝謝,有點令人驚訝,沒有人喜歡它 – emmby 2011-03-07 20:16:35

+0

你會認爲他們會提供這樣的一個,我也很驚訝。我想這是作爲練習留給用戶的嗎? :) – sjlee 2011-03-07 20:19:25

0

由於Java 8,你可以使用CompletableFuture<T>。線程A可以使用阻塞方法get()等待結果,而線程B可以使用complete()傳遞計算結果。

如果線程B在計算結果時遇到異常,它可以通過調用completeExceptionally()與線程A進行通信。

相關問題