多线程:2个线程之间的数据交换器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();
    }
}

运行日志如下:

a
a
账单没问题1662026332330
d
b
账单不对
c
c
账单没问题1662026332330

思路解释:有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();
    }
}

运行日志:

tail等待交换。。。。1662026718504

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

(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();
    }
}

运行日志:

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)

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行云的逆袭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值