前言
上面我们介绍了信号量,再来说说交换者,这个东西用的不是很多,所以一般也不被经常关注,但是我们还是最好了解下,下面我将从什么是Exchanger以及如何使用Exchanger两个方面谈谈这个用于线程间协调的工具类。
什么是Exchanger?
Exchanger主要是用于线程之间进行数据交换的,提供一个同步点,在这个同步点,两个线程可以交换彼此的数据;两个线程通过Exchanger方法来进行交换,当第一个线程先执行Exchanger()方法,他会一直等待第二个线程也执行Exchanger方法,然后两个线程交换数据。
举个通俗点的例子,就例如,你和你女朋友一起去逛超市,然后进入超市之后,你俩约好每个人去买各自需要的用品,然后约好在结算台那里见面,不管你俩谁先买好东西到达服务台,都需要把东西放在服务台然后等待对方,当你俩都到达结账台时,你俩互相交换各自买的东西,看看对方都买了些啥(当然如果你跟你女朋友真是这么逛街的,估计也处不长,扯远了点),然后结账,完事。这个过程就是Exchanger交换数据过程,而你俩分别就是那两个线程。
如何使用Exchanger?
首先我们需要一个创建一个交换者
ExchangerString exgr = new ExchangerString();
然后到达同步点,等待交换:
public V exchange(V x) throws InterruptedException {
if (!Thread.interrupted()) {
Object v = doExchange((x == null) ? NULL_ITEM : x, false, 0);
if (v == NULL_ITEM)
return null;
if (v != CANCEL)
return (V)v;
Thread.interrupted(); // Clear interrupt status on IE throw
}
throw new InterruptedException();
}
下面我们来看示例,模拟你和女朋友逛超市:
public class ExchangerDemo {
// 超市结账服务台(同步点)
private static final ExchangerString exgr = new ExchangerString();
// 你和你女朋友
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
System.out.println("逛街开始,行动!!!");
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("你进入超市");
try {
String u = "电子产品";
System.out.println("你购买ok,到达服务台");
// 到达同步点,等待或者交换(所有线程都到达)
exgr.exchange(u);
} catch (InterruptedException e) {
}
}
});
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println("女朋友进入超市");
try {
String girlfriend = "化妆品";
// 交换购买物品 到达同步点,等待或者交换(所有线程都到达)
String u1 = exgr.exchange("girlfriend");
System.out.println("女朋友到达服务台,交换购买物品");
System.out.println("你购买的是:"
+ u1 + ",女朋友购买的是:" + girlfriend);
} catch (InterruptedException e) {
}
}
});
threadPool.shutdown();
}
}
执行结果:
当然还有一种情况,就是可能会你和你女朋友分开逛街的过程中,出现点状况,导致你买好东西之后,在服务台一直等她,她都没来(没来原因自己脑补),然后你也不能一直等下去啊,然后你就自己结账走人了,然后,然后,你就单身了…,对于这种情况,Exchanger提供了一个超时交换的方法,设置最大等待时间,源代码如下:
public V exchange(V x, long timeout, TimeUnit unit)
throws InterruptedException, TimeoutException {
if (!Thread.interrupted()) {
Object v = doExchange((x == null) ? NULL_ITEM : x,
true, unit.toNanos(timeout));
if (v == NULL_ITEM)
return null;
if (v != CANCEL)
return (V)v;
if (!Thread.interrupted())
throw new TimeoutException();
}
throw new InterruptedException();
}
原文始发于微信公众号(Justin的后端书架):