2011-03-07 222 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进行通信。

相关问题