• 看完抱你学会Exchanger


    Exchanger用于两个线程之间进行数据交换,每个线程调用exchage方法到达各自的同步点,当且仅当两个线程都达到同步点的时候,才可以交换信息,否则先到达同步点的线程必须等待

    Exchanger仅可用作两个线程之间的信息交换,当超过2个线程调用同一个Exchanger时,得到的结果是不可预料的。

    上面的话需要好好理解
    (1)验证数据交换

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Exchanger;
    
    public class ExchangerTest1 {
    
        public static void main(String[] args) {
        	//初始化一个交换器
            Exchanger<String> exchanger = new Exchanger<>();
            List<String> tails1 = new ArrayList<>();
            tails1.add("a");
            tails1.add("b");
            tails1.add("c");
            List<String> tails2 = new ArrayList<>();
            tails2.add("a");
            tails2.add("d");
            tails2.add("c");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (String tail:tails1) {
                            String tail1 = exchanger.exchange(tail);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (String tail:tails2) {
                            String tail1 = exchanger.exchange(tail); 
                            System.out.println(tail);
                            System.out.println(tail1);
                            if (tail.equals(tail1)){
                                System.out.println("账单没问题" + System.currentTimeMillis());
                            }else{
                                System.out.println("账单不对");
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    运行日志如下:

    a
    a
    账单没问题1662026332330
    d
    b
    账单不对
    c
    c
    账单没问题1662026332330
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    思路解释:有2个数组tails1和tails2,利用2个线程对比2个数组是否一致。2个线程通过Exchanger逐个交换数据进行对比验证,可以验证出第二个数字不一致。

    (2)验证同步点等待

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Exchanger;
    
    public class ExchangerTest1 {
    
        public static void main(String[] args) {
        	//初始化一个交换器
            Exchanger<String> exchanger = new Exchanger<>();
            List<String> tails1 = new ArrayList<>();
            tails1.add("a");
            tails1.add("b");
            tails1.add("c");
            List<String> tails2 = new ArrayList<>();
            tails2.add("a");
            tails2.add("d");
            tails2.add("c");
            /*
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (String tail:tails1) {
                            String tail1 = exchanger.exchange(tail);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();*/
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (String tail:tails2) {
                        	System.out.println("tail等待交换。。。。" + System.currentTimeMillis());
                            String tail1 = exchanger.exchange(tail); 
                            System.out.println(tail);
                            System.out.println(tail1);
                            if (tail.equals(tail1)){
                                System.out.println("账单没问题" + System.currentTimeMillis());
                            }else{
                                System.out.println("账单不对");
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    运行日志:

    tail等待交换。。。。1662026718504
    
    • 1

    只有一个线程运行时,没有其他线程与之交换,因此没有同时达到同步点,会一直阻塞。就像一开始说的:先到达同步点的线程必须等待。

    (3)阻塞可以设置一个时间限制,等待到一定时间抛出异常,如下验证

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Exchanger;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;
    
    public class ExchangerTest1 {
    
        public static void main(String[] args) {
            Exchanger<String> exchanger = new Exchanger<>();
            List<String> tails1 = new ArrayList<>();
            tails1.add("a");
            tails1.add("b");
            tails1.add("c");
            List<String> tails2 = new ArrayList<>();
            tails2.add("a");
            tails2.add("d");
            tails2.add("c");
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (String tail:tails2) {
                           System.out.println("tail等待交换。。。。" + System.currentTimeMillis());
                           //等待5秒
                            String tail1 = exchanger.exchange(tail,5, TimeUnit.SECONDS);
                            System.out.println(tail);
                            System.out.println(tail1);
                            if (tail.equals(tail1)){
                                System.out.println("账单没问题" + System.currentTimeMillis());
                            }else{
                                System.out.println("账单不对");
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (TimeoutException e) {
                        System.out.println("等待交换超时。。。。" + System.currentTimeMillis());
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    运行日志:

    tail等待交换。。。。1662026956498
    等待交换超时。。。。1662026961500
    java.util.concurrent.TimeoutException
    	at java.util.concurrent.Exchanger.exchange(Exchanger.java:626)
    	at com.example.demo.thread.ExchangerTest1$1.run(ExchangerTest1.java:41)
    	at java.lang.Thread.run(Thread.java:748)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    超时时间:(1662026961500-1662026956498)/1000=5,差不多就是5秒超时

    可以得出结论,没有达到同步点,确实在阻塞。

    (4)如果超过2个线程交换信息,可能会造成信息的错乱,A线程的数据会和C线程交换,而C又和B进行交换,显然是无法保证交换结果。此处不做代码验证。

  • 相关阅读:
    使用AOP做日志切面
    .NET周刊【8月第1期 2023-08-06】
    成都优优聚代运营:打造精细化运营新标杆
    前 Twitter CEO 炮轰 Web 3,马斯克也来“掺和一脚”
    Rust 流程控制和循环控制
    c++ primer中文版第五版作业第二章
    Opencv形态学——腐蚀、膨胀、开运算与闭运算、梯度运算、礼帽、黑帽
    DC/DC开关电源学习笔记(九)Buck降压拓扑原理
    靶机20 driftingblues3
    软件测试入门学习笔记
  • 原文地址:https://blog.csdn.net/juligang320/article/details/126648490