JUC中的Exchanger允许成对的线程在指定的同步点上通过exchange方法来交换数据。如果第一个线程先执行exchange方法,它会一直等待第二个线程也 执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将当前线程生产 出来的数据传递给对方。

Exchanger示例

两个线程通过Exchanger交换数据的简单示例: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

27public class ExchangerTest{

public static void main(String[] args){

final Exchanger exchanger = new Exchanger<>();

new Thread(() -> {

System.out.println("thread1开始");

try {

String exchange = exchanger.exchange("来自thread1的数据");

System.out.println("接收thread2发送的数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread1结束");

}, "thread1").start();

new Thread(() -> {

System.out.println("thread2开始");

try {

String exchange = exchanger.exchange("来自thread2的数据");

System.out.println("接收thread1发送的数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread2结束");

}, "thread2").start();

}

}

在定义Exchanger的时候需要指定交换的数据类型,这里为String类型。exchange方法用于向另一个线程发送数据,方法的返回值为另一个线程发送过来的数据。上面例子输出如下:1

2

3

4

5

6thread1开始

thread2开始

接收thread2发送的数据:来自thread2的数据

thread1结束

接收thread1发送的数据:来自thread1的数据

thread2结束

上面说过,只有当成对的线程都到达同步点的时候,才会执行数据交换操作。现在我们让thread2休眠一会儿,看看thread1是否会进入等待: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

28public class ExchangerTest{

public static void main(String[] args){

final Exchanger exchanger = new Exchanger<>();

new Thread(() -> {

System.out.println("thread1开始");

try {

String exchange = exchanger.exchange("来自thread1的数据");

System.out.println("接收thread2发送的数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread1结束");

}, "thread1").start();

new Thread(() -> {

System.out.println("thread2开始");

try {

TimeUnit.SECONDS.sleep(3); // thread1也会进入等待,直到双方都准备好交换数据。

String exchange = exchanger.exchange("来自thread2的数据");

System.out.println("接收thread1发送的数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread2结束");

}, "thread2").start();

}

}

程序输出如下所示:

那么如果线程不成对会出现什么情况呢?我们添加thread3线程: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

38public class ExchangerTest{

public static void main(String[] args){

final Exchanger exchanger = new Exchanger<>();

new Thread(() -> {

System.out.println("thread1开始");

try {

String exchange = exchanger.exchange("发送数据-thread1");

System.out.println("接收数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread1结束");

}, "thread1").start();

new Thread(() -> {

System.out.println("thread2开始");

try {

String exchange = exchanger.exchange("发送数据-thread2");

System.out.println("接收数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread2结束");

}, "thread2").start();

new Thread(() -> {

System.out.println("thread3开始");

try {

String exchange = exchanger.exchange("发送数据-thread3");

System.out.println("接收数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread3结束");

}, "thread3").start();

}

}

程序输出如下所示:1

2

3

4

5

6

7thread1开始

thread3开始

接收数据:发送数据-thread1

thread3结束

thread2开始

接收数据:发送数据-thread3

thread1结束

可看到thread1和thread3交换了数据然后正常停止了,而thread2由于没有线程和它交换数据而苦苦等待,线程永远不会停止。查看线程快照可以证明这点:

线程匹配是随机的,所以也有可能thread1和thread2匹配,thread3进入无休止的等待,这就类似于…

另一个值得一提的点就是通过Exchanger交换的是同一个对象,而不是对象的拷贝: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

31public class ExchangerTest{

public static void main(String[] args){

final Exchanger exchanger = new Exchanger<>();

new Thread(() -> {

System.out.println("thread1开始");

Object object = new Object();

System.out.println("thread1发送数据:" + object);

try {

Object exchange = exchanger.exchange(object);

System.out.println("接收thread2发送的数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread1结束");

}, "thread1").start();

new Thread(() -> {

System.out.println("thread2开始");

Object object = new Object();

System.out.println("thread2发送数据:" + object);

try {

Object exchange = exchanger.exchange(object);

System.out.println("接收thread1发送的数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread2结束");

}, "thread2").start();

}

}

程序输出如下:1

2

3

4

5

6

7

8thread1开始

thread2开始

thread2发送数据:java.lang.Object@6d559005

thread1发送数据:java.lang.Object@7702c19

接收thread2发送的数据:java.lang.Object@6d559005

接收thread1发送的数据:java.lang.Object@7702c19

thread2结束

thread1结束

可以看到thread1发送的对象和thread2接收的对象句柄是一致的。

设置超时时间

如果不想线程在交换数据的时候等待过长的时间,我们可以使用exchanger的重载方法exchange(V x, long timeout, TimeUnit unit)来指定超时时间: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

28public class ExchangerTest{

public static void main(String[] args){

final Exchanger exchanger = new Exchanger<>();

new Thread(() -> {

System.out.println("thread1开始");

try {

String exchange = exchanger.exchange("来自thread1的数据", 5, TimeUnit.SECONDS);

System.out.println("接收thread2发送的数据:" + exchange);

} catch (InterruptedException | TimeoutException e) {

e.printStackTrace();

}

System.out.println("thread1结束");

}, "thread1").start();

new Thread(() -> {

System.out.println("thread2开始");

try {

TimeUnit.SECONDS.sleep(10);

String exchange = exchanger.exchange("来自thread2的数据");

System.out.println("接收thread1发送的数据:" + exchange);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("thread2结束");

}, "thread2").start();

}

}

上面例子中,thread2休眠10秒后才开始交换数据,而thread1在等待5秒后没能成功交换数据就抛出TimeoutException异常了。10秒后由于没有线程再和thread2交换数据,所以thread2会一直等待:

java juc exchanger_JUC之Exchanger相关推荐

  1. java juc exchanger_JUC——Exchanger

    A synchronization point at which threads can pair and swap elements within pairs. Each thread presen ...

  2. Java JUC工具类--Exchanger

    Exchanger Exchanger用于进行线程间的数据交换,它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据 两个线程通过exchange方法交换数据,如果一个线程先执行exchange ...

  3. java juc exchanger_JUC工具类实例

    描述 本文描述了JUC中CountDownLatch.CyclicBarrier.Semaphore.Exchanger工具类使用方式. CountDownLatch 以下代码为例:主线程阻塞直到Co ...

  4. Java JUC学习 - ConcurrentLinkedDeque 详解

    Java JUC学习 - ConcurrentLinkedDeque 详解 0x00 前言 如何实现并发程序,对于Java以及其他高级语言来说都是一件并不容易的事情.在大一上学期的时候,我们学习了链表 ...

  5. Java JUC并发编程详解

    Java JUC并发编程详解 1. JUC概述 1.1 JUC简介 1.2 进程与线程 1.2 并发与并行 1.3 用户线程和守护线程 2. Lock接口 2.1 Synchronized 2.2 什 ...

  6. Java JUC高并发编程(三)-CallableJUC辅助类

    目录 一.Callable接口 二.JUC辅助类 1.减少计数CountDownLatch 2.循环栅栏CyclicBarrier 3.信号灯Semaphore 一.Callable接口 Callab ...

  7. Java juc系列6 —— 线程池

    Java JUC系列目录链接 Java 线程池核心原理解析 Java线程池的基础用法 创建和使用 为什么需要线程池 线程的生命周期[^1] 新建 就绪 运行 休眠 终止 使用线程的代价 线程池帮我们做 ...

  8. Java JUC系列

    1.Java JUC 简介 2.volatile 关键字-内存可见性 3.原子变量 CAS算法 4.ConcurrentHashMap 锁分段机制 5.CountDownLatch 闭锁 6.实现 C ...

  9. Java JUC高并发编程(一)

    目录 一.概述 二.Lock接口 三.线程间的通信 解决虚假唤醒问题 Lock通信示例: 四.线程间定制化通信 一.概述 JUC就是java.util.concurrent工具包的简称,这是一个处理线 ...

最新文章

  1. h265player开发
  2. 祝大家春节快乐身体健康
  3. 本地环境的搭配及安装配置
  4. C#编程中的crc16校验
  5. python 路由转发_RabbitMQ之路由键转发消息
  6. 【机器学习基础】数学推导+纯Python实现机器学习算法18:奇异值分解SVD
  7. mysql数据库入门第二张试卷_2016计算机二级《MySQL数据库》练习题与答案
  8. OScached页面缓存的入门使用
  9. ABAP Development Tools的语法高亮实现原理
  10. 简化 Pod 故障诊断:kubectl-debug 介绍
  11. Nuget如何自动下载依赖DLL引用
  12. 这个韩国女星在节目里吃了“巨型蛤蜊” 可能要坐牢5年了...
  13. Objective-C的算术表达式
  14. Could not resolve type alias ‘‘
  15. python多PDF文件合成一个
  16. myline java线段类,MyLine 编写一个线段类 MyLine 联合开发网 - pudn.com
  17. linux 查看IP地址
  18. 详解 python 的 切片
  19. 自然语言处理是什么,我们为什么需要处理自然语言?
  20. managed-schema配置文件详解

热门文章

  1. 腾讯投资的功成、错失与未知
  2. Java中关于包装类的练习题
  3. gulp系列之gulp-uglify插件的使用
  4. PPPoE的封装结构(经典 解释了PPPoE中虚拟网卡的作用)
  5. pyecharts的绘图原理详解
  6. 米达机器人_《星球大战》历史中最佳机器人排名TOP10,你知道几个?
  7. HISAT2 - StringTie - DESeq2 pipeline 进行bulk RNA-seq
  8. 2018年网易校招内推编程题之交错01串
  9. AE中Add-In插件开发实例
  10. 小班语言游戏教案%3c我的五官%3e,小班《我的五官》教案