Exchanger类的使用及常用API

Exchanger类

类Exchanger的功能可以使两个线程之间传输数据,它比生产者消费者模式使用的wait/notify更加方便。
Exchanger类可用于两个线程之间交换信息。可简单地将Exchanger对象理解为一个包含两个格子的容器,通过exchanger方法可以向两个格子中填充信息。当两个格子中的均被填充时,该对象会自动将两个格子的信息交换,然后返回给线程,从而实现两个线程的信息交换。

方法exchange()传递数据

V exchange(V x) 方法,用于两个线程交换数据,返回值V是取得的交换的数据,参数V是用于交换的数据。只有当两个线程都放入数据才会相互交互。
示例中创建了两个线程,线程在执行过程中,调用同一个exchanger对象的exchange方法,进行信息通信,当两个线程均已将信息放入到exchanger对象中时,exchanger对象会将两个线程放入的信息交换,然后返回。

public class ExchangeDemo {
    public static class MyThread extends Thread{
        //用于数据交换
        private Exchanger<String> exchanger;

        public MyThread(String name, Exchanger<String> exchanger) {
            super(name);
            this.exchanger = exchanger;
        }

        @Override
        public void run() {
            try {
                //exchange()方法存放String用于跟其他线程交换,如果其他线程也在exchange()方法中存储了就会互相交换
                //当前exchange()方法的参数是String类型,返回值也是String类型
                System.out.println(Thread.currentThread().getName() + "取得其他的用于交换的数据:" + exchanger.exchange(Thread.currentThread().getName()+"存放的数据"));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<String>();
        MyThread myThreadA = new MyThread("线程A",exchanger);
        MyThread myThreadB = new MyThread("线程B",exchanger);
        myThreadA.start();
        myThreadB.start();
    }
}
线程B取得其他的用于交换的数据:线程A存放的数据
线程A取得其他的用于交换的数据:线程B存放的数据

方法exchange()堵塞的特性

如果只有一个线程执行了exchange()方法,没有另一个线程执行,会怎么样呢?该线程会一直等待,一直堵塞等待。

public class ExchangeDemo {
    public static class MyThread extends Thread{
        //用于数据交换
        private Exchanger<String> exchanger;

        public MyThread(String name, Exchanger<String> exchanger) {
            super(name);
            this.exchanger = exchanger;
        }

        @Override
        public void run() {
            try {
                //exchange()方法存放String用于跟其他线程交换,如果其他线程也在exchange()方法中存储了就会互相交换
                //当前exchange()方法的参数是String类型,返回值也是String类型
                //如果没有其他线程跟其交换数据,会一直堵塞等待!
                System.out.println(Thread.currentThread().getName() + "取得其他的用于交换的数据:" + exchanger.exchange(Thread.currentThread().getName()+"存放的数据"));
                //不会执行,因为没有线程 跟其交换数据,会一直在上面的exchange()方法处堵塞等待
                System.out.println(Thread.currentThread().getName()+"在等待数据交换");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Exchanger<String> exchanger = new Exchanger<String>();
        MyThread myThreadA = new MyThread("线程A",exchanger);
        myThreadA.start();
        Thread.sleep(1000);
        System.out.println("线程启动了");
    }
}
线程启动了

上面的线程一直堵塞等待其他线程跟其交换数据。

多个线程执行方法exchange()传递数据

下面的代码创建了3个线程,而线程的交换是两两交换的,所以奇数个线程,始终会有一个线程一直在等待交换,一直在堵塞,另外两个线程会完成交换。偶数线程不会存在这种情况,但是不管奇数个线程还是偶数个线程,线程的数据交互是随机,可能A跟B交换,可能A跟C交换。

public class ExchangeDemo {
    public static class MyThread extends Thread{
        //用于数据交换
        private Exchanger<String> exchanger;

        public MyThread(String name, Exchanger<String> exchanger) {
            super(name);
            this.exchanger = exchanger;
        }

        @Override
        public void run() {
            try {
                //exchange()方法存放String用于跟其他线程交换,如果其他线程也在exchange()方法中存储了就会互相交换
                //当前exchange()方法的参数是String类型,返回值也是String类型
                //如果没有其他线程跟其交换数据,会一直堵塞等待!
                System.out.println(Thread.currentThread().getName() + "取得其他的用于交换的数据:" + exchanger.exchange(Thread.currentThread().getName()+"存放的数据"));
                //如果没有线程跟其交换数据,不会执行,因为没有线程 跟其交换数据,会一直在上面的exchange()方法处堵塞等待
                System.out.println(Thread.currentThread().getName()+"完成数据交换");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Exchanger<String> exchanger = new Exchanger<String>();
        MyThread myThreadA = new MyThread("线程A",exchanger);
        MyThread myThreadB = new MyThread("线程B",exchanger);
        MyThread myThreadC = new MyThread("线程C",exchanger);
        myThreadA.start();
        myThreadB.start();
        myThreadC.start();
    }
}
线程B取得其他的用于交换的数据:线程C存放的数据
线程C取得其他的用于交换的数据:线程B存放的数据
线程B完成数据交换
线程C完成数据交换

本次执行,是BC交换数据,A线程一直在等待数据交换。

方法exchange(V x, long timeout, TimeUnit unit)与超时

当调用exchange(V x, long timeout, TimeUnit unit)方法后在指定的时间内没有其他线程获取数据,则出现超时异常。

public class ExchangeDemo {
    public static class MyThread extends Thread{
        //用于数据交换
        private Exchanger<String> exchanger;

        public MyThread(String name, Exchanger<String> exchanger) {
            super(name);
            this.exchanger = exchanger;
        }

        @Override
        public void run() {
            try {
                //exchange()方法存放String用于跟其他线程交换,如果其他线程也在exchange()方法中存储了就会互相交换
                //当前exchange()方法的参数是String类型,返回值也是String类型
                //如果没有其他线程跟其交换数据,会一直堵塞等待!
                System.out.println(Thread.currentThread().getName() + "取得其他的用于交换的数据:" + exchanger.exchange(Thread.currentThread().getName()+"存放的数据",3, TimeUnit.SECONDS));
                //如果没有线程跟其交换数据,不会执行,因为没有线程 跟其交换数据,会一直在上面的exchange()方法处堵塞等待
                System.out.println(Thread.currentThread().getName()+"完成数据交换");
            } catch (InterruptedException | TimeoutException e) {
                System.out.println(Thread.currentThread().getName()+"报超时异常");
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Exchanger<String> exchanger = new Exchanger<String>();
        MyThread myThreadA = new MyThread("线程A",exchanger);
        MyThread myThreadB = new MyThread("线程B",exchanger);
        MyThread myThreadC = new MyThread("线程C",exchanger);
        myThreadA.start();
        myThreadB.start();
        myThreadC.start();
    }
}
线程A取得其他的用于交换的数据:线程C存放的数据
线程A完成数据交换
线程C完成数据交换

线程B报超时异常
java.util.concurrent.TimeoutException
	at java.base/java.util.concurrent.Exchanger.exchange(Exchanger.java:627)
	at com.example.demo.ExchangeDemo$MyThread.run(ExchangeDemo.java:23)

总结

类Semaphore 的主要作用是限制并发执行的线程个数,它具有 synchronized 所不具有的强大功能,比如等待获得许可的同时可以加入等待时间,还有尝试是否可以持有锁等这类扩展功能,可以说 Semaphore 类是强有力的控制并发线程个数的解决方案之一,而 Exchanger是线程间传输数据的方式之 ,而且在传输的数据类型上并没有任何限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值