JUC中的Exchanger允许成对的线程在指定的同步点上通过exchange
方法来交换数据。如果第一个线程先执行exchange
方法,它会一直等待第二个线程也 执行exchange
方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将当前线程生产 出来的数据传递给对方。
Exchanger示例
两个线程通过Exchanger交换数据的简单示例:
1 | public class ExchangerTest { |
在定义Exchanger的时候需要指定交换的数据类型,这里为String类型。exchange
方法用于向另一个线程发送数据,方法的返回值为另一个线程发送过来的数据。上面例子输出如下:
1 | thread1开始 |
上面说过,只有当成对的线程都到达同步点的时候,才会执行数据交换操作。现在我们让thread2休眠一会儿,看看thread1是否会进入等待:
1 | public class ExchangerTest { |
程序输出如下所示:
那么如果线程不成对会出现什么情况呢?我们添加thread3线程:
1 | public class ExchangerTest { |
程序输出如下所示:
1 | thread1开始 |
可看到thread1和thread3交换了数据然后正常停止了,而thread2由于没有线程和它交换数据而苦苦等待,线程永远不会停止。查看线程快照可以证明这点:
线程匹配是随机的,所以也有可能thread1和thread2匹配,thread3进入无休止的等待,这就类似于…
另一个值得一提的点就是通过Exchanger交换的是同一个对象,而不是对象的拷贝:
1 | public class ExchangerTest { |
程序输出如下:
1 | thread1开始 |
可以看到thread1发送的对象和thread2接收的对象句柄是一致的。
设置超时时间
如果不想线程在交换数据的时候等待过长的时间,我们可以使用exchanger
的重载方法exchange(V x, long timeout, TimeUnit unit)
来指定超时时间:
1 | public class ExchangerTest { |
上面例子中,thread2休眠10秒后才开始交换数据,而thread1在等待5秒后没能成功交换数据就抛出TimeoutException
异常了。10秒后由于没有线程再和thread2交换数据,所以thread2会一直等待: