java Exchanger在两条线程之间交换数据

是什么?为什么?怎么做?

 

一、是什么

Exchanger是java包提供的一个同步类。

当线程A调用Exchange对象的exchange方法后,会陷入阻塞状态,直到线程B也调用exchange方法,然后线程A、B之间以线程安全的方式交换数据,之后线程A和B继续运行。

Exchanger使用起来也有其局限性。Exchange类只能同步2个线程,也就是说只能在两条线程之间交换数据。如果有更多的线程就无能为力了。

二、为什么

现在给出一个情景:

线程A希望在其执行过程中获取线程B在执行过程中的中间产物,如何实现?

记得之前讨论了线程如何获取其他线程的结果:

http://www.xie4ever.com/2017/03/23/java-future%E5%92%8Cfuturetask%E8%8E%B7%E5%8F%96%E7%BA%BF%E7%A8%8B%E5%BC%82%E6%AD%A5%E6%89%A7%E8%A1%8C%E7%9A%84%E7%BB%93%E6%9E%9C/

以上的方法是线程执行完毕之后才能获取结果(要确保线程执行完毕),不适用于此情景。如果在在程执行中获取,我们又不知道线程执行到了哪里,不能获取我们想要的中间产物。

所以有这样一个解决方法,当线程执行到的某个时间点时,阻塞线程,这时候通过get方法/共享变量的方法获取中间结果,再让线程继续执行。

我认为这种方式就是Exchange的思想。当线程A调用Exchange对象的exchange方法后,会陷入阻塞状态,直到线程B也调用exchange方法,然后线程A、B之间以线程安全的方式交换数据,之后线程A和B继续运行。

使用Exchange可以较好地解决上面情景中的问题。

三、怎么做

1.简单例子

这里的exchange方法设置了超时时间:

如果超时,将报出java.util.concurrent.TimeoutException错误,可以在try catch中采取一些后续措施。

输出结果:

 

2.一个让我不解的问题

上面的程序在子线程执行完后,应该直接退出才对。但是事实是还需要等待一段时间,才会退出运行。

看了一下,我认为不是子线程写得有问题,所以问题应该出在:

这个部分。为了求证,我替换成了:

果然没有再出现这个问题。

我的理解:线程池处理完线程之后,没有主动关闭。所以主线程中还有线程池在运行,没有退出。

加上一个shutdown方法,就不会出现这个问题了:

四、总结

如果需要获得线程的预期结果,使用future。

如果需要获得线程的中间结果,使用Exchanger。

发表评论

电子邮件地址不会被公开。 必填项已用*标注