并发(六):用Exchanger实现数据交换

来源:互联网 发布:vgg19网络结构图 编辑:程序博客网 时间:2024/05/21 17:26

在多线程程序的设计中,最难处理就是各线程之间的耦合关系,所以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只能处理两个线程间的数据交换,完全是错误的说法)。