在多线程程序的设计中,最难处理就是各线程之间的耦合关系,所以JDK提供了很多用于解耦的类,例如BlockingQueue、BlockingDeque等,这些类的特点是既可以适用于消费者/生产者模式,还可以适用于消费者与生产者混合模式。
今天介绍的Exchanger除了在数据交换方面表现得非常优秀之外,还能协调线程的执行进度,而且是多个线程(并没有一对一之间的关系)之间的进度,所有特别适用于分发任务,下面给出一个最简单的代码示例:
static class Consumer implements Runnable {
private Exchanger<Integer> exchanger;
// 确定是否是基数消费器
private boolean odd;
/**
* @param exchanger
* @param odd
*/
public Consumer(Exchanger<Integer> exchanger, boolean odd) {
super();
this.exchanger = exchanger;
this.odd = odd;
}
public void run() {
int remain = odd ? 1 : 0;
String output = odd ? "收到偶数:" : "收到奇数:";
try {
for(int i =0; i < 3; i++) {
if(i % 2 == remain) {
// 奇数与偶数交换数据
int result = exchanger.exchange(i);
System.out.println(output + result);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
主函数代码如下:
public static void main(String[] args) {
Exchanger<Integer> ex = new Exchanger<>();
// 发送奇数,消费偶数
new Thread(new Consumer(ex, true)).start();
// 发送偶数,消费奇数
new Thread(new Consumer(ex, false)).start();
}
最后输出结果如下:
收到偶数:0
收到奇数:1
但出现了一个问题,线程无法终结,一直处于运行状态,这是因为偶数比奇数多一个,导致偶数交换线程一直在等待消费线程,解决办法有两种:
1. 双方的数量保持一致;
2. 在数据交换时加上时间限制,如下:
int result = exchanger.exchange(i, 3, TimeUnit.SECONDS);
结论
Exchanger除了能交换数据,还能协调线程的执行进度,并且能协调多个线程的进度与数据交换(网上的很多文章都说Exchanger只能处理两个线程间的数据交换,完全是错误的说法)。