【问题标题】:How to have one java thread wait for the result of another thread?如何让一个java线程等待另一个线程的结果?
【发布时间】:2011-07-10 11:40:41
【问题描述】:

我经常需要让一个线程等待另一个线程的结果。好像java.util.concurrent中应该有对此的一些支持,但是我找不到。

Exchanger 与我所说的非常接近,但它是双向的。我只希望线程 A 在线程 B 上等待,而不是让两者互相等待。

是的,我知道我可以使用 CountDownLatch 或 Semaphore 或 Thread.wait() 然后自己管理计算结果,但似乎我必须在某个地方缺少一个便利类。

我错过了什么?

更新

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

【问题讨论】:

标签: java multithreading java.util.concurrent


【解决方案1】:

从 Java 8 开始,您可以使用 CompletableFuture&lt;T&gt;。线程 A 可以使用阻塞 get() 方法等待结果,而线程 B 可以使用 complete() 传递计算结果。

如果线程 B 在计算结果时遇到异常,它可以通过调用 completeExceptionally() 将其传达给线程 A。

【讨论】:

    【解决方案2】:

    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
    }
    

    【讨论】:

    • 这就是我正在寻找的那种课程,谢谢。有点令人惊讶的是还没有这样的人。
    • 你会认为他们会提供这样的,我也很惊讶。我猜它是留给用户作为练习的? :)
    【解决方案3】:

    您可以为此使用 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();
    

    【讨论】:

    • 我怀疑 OP 已经意识到这一点:“是的,我知道我可以使用 CountDownLatch 或 ...”
    • '是的,我知道我可以使用 CountDownLatch 或 Semaphore 或 Thread.wait() 然后自己管理计算结果,但似乎我必须在某处缺少便利类。 '
    【解决方案4】:

    到目前为止,BlockingQueue 似乎是我找到的最佳解决方案。

    例如。

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

    等待线程调用queue.take()等待结果,生产队列调用queue.add()提交结果。

    【讨论】:

      【解决方案5】:

      我最近遇到了同样的问题,尝试使用 Future 然后使用 CountdownLatch,但最终选择了 Exchanger。它们应该允许两个线程交换数据,但是没有理由为什么其中一个线程不能只传递一个空值。

      最后,我认为这是最干净的解决方案,但这可能取决于您想要实现的具体目标。

      【讨论】:

      • 这与我发现自己的情况完全相同。很高兴听到这不仅仅是我。现在我正在尝试确定 BlockingQueue 或 Exchanger(或其他东西)是否是最干净的范例
      【解决方案6】:

      使用Thread.join()有什么不方便的地方?

      【讨论】:

      • 我认为他想等待一个线程修改一个值而不是等待一个线程完成他的工作,不是吗?
      【解决方案7】:

      您在寻找Future&lt;T&gt; 吗?这是已(通常)提交到工作队列但可能尚未完成的任务的正常表示。您可以查看其完成状态、阻塞直到完成等。

      查看ExecutorService获取期货的正常方式。请注意,这侧重于获取单个任务的结果,而不是等待线程完成。当然,单个线程可能在其生命周期内完成许多任务 - 这就是线程池的全部意义所在。

      【讨论】:

      • Future 的问题是我还需要使用 CountdownLatch 或其他一些同步机制来管理结果何时可用。它最终是比仅仅使用 Exchanger 更多的代码(我相信)
      • @emmby:你为什么需要这样做?如果您对阻塞感到满意,只需从消费线程调用future.get()。如果需要,请添加超时。目前尚不清楚为什么这对你不起作用......唯一的问题是产生值的线程是否仍然意味着继续做其他事情......你还没有把大局看得很清楚。
      • 嗨,乔恩,我用一个例子更新了这个问题,希望能证明我在说什么。
      • @emmby:好吧,看起来未来会很好。您可以从Callable&lt;T&gt; 实现中返回它,而不是显式设置该值,该实现将被提交给执行程序服务并包装在Future&lt;T&gt; 中。
      • 我不反对它可以做到。您不认为 Exchanger 或 BlockingQueue 解决方案不那么冗长且更易于理解吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-22
      • 2017-09-28
      • 1970-01-01
      • 2015-02-22
      • 2021-06-21
      • 1970-01-01
      相关资源
      最近更新 更多