Exchanger交换空间

如果现在有两个线程,一个线程负责生产数据,另外一个线程负责消费数据,那么这个两个线程之间一定会存在一个公共的区域,那么这个区域的实现在JUC包之中称为Exchanger

java.util.concurrent.Exchanger类表示一种两个线程可以进行互相交换对象的汇合点。

Exchanger类中定义的方法如下:

  • 构造方法:

    pubilc Exchanger();  //创建一个对象
  • 设置与取得:
    public V exchange(V x) throws InterruptedException

范例:使用Exchanger实现交换处理

package so.strong.mall.concurrent;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit; public class ExchanerDemo {
public static void main(String[] args) {
final Exchanger<String> exchanger = new Exchanger<>(); //准备一个交换空间
for (int i = 0; i < 3; i++) { //3个消费者
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
String data = exchanger.exchange(null);
TimeUnit.SECONDS.sleep(2);
if (data != null) {
System.out.println("[" + Thread.currentThread().getName() + "]取得数据:" + data);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "消费者-" + i).start();
} for (int i = 0; i < 2; i++) { //2个生产者
final int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 2; j++) {
String data = "iTermis-" + temp + "-" + j;
try {
TimeUnit.SECONDS.sleep(2); //让生产者节奏放慢
exchanger.exchange(data);
System.out.println("[" + Thread.currentThread().getName() + "]生产了数据:" + data);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "生产者-" + i).start();
}
}
}
[生产者-1]生产了数据:iTermis-1-0
[生产者-1]生产了数据:iTermis-1-1
[消费者-1]取得数据:iTermis-1-0
[生产者-0]生产了数据:iTermis-0-0
[生产者-0]生产了数据:iTermis-0-1
[消费者-2]取得数据:iTermis-0-1

  

CompletableFuture线程回调

现在设想一个场景,例如:使用炮兵轰炸某一目标

所有的执行线程在接收到命令之前都要进入到阻塞状态之中,一直到接收到具体的命令之后才会执行下一步操作处理。

java.util.concurrent.CompletableFutureJava8中添加的一个类,该类的主要作用是提供了新的方式来完成异步处理,包括合成和组合事件的非阻塞方式。

CompletableFuture类中有如下的方法:

  • 构造方法:

    public CompletableFuture();
  • 获取命令:
    public T get() throws InterruptedException,ExecutionException  

范例:使用CompletableFuture实现炮兵轰炸操作

package com.itermis.concurrent;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<String> future = new CompletableFuture<>();
for (int i = 0; i < 4; i++) {
new Thread(() -> {
System.out.println("BEFORE[" + Thread.currentThread().getName() + "]进入炮兵阵地,等待命令,准备开火。");
try {
String cmd = future.get(); //接收命令
if ("fire".equals(cmd)) {
System.out.println("AFTER[" + Thread.currentThread().getName() + "]接收到命令,立刻开火,干死那个死胖子。。");
}
if ("cancel".equals(cmd)) {
System.out.println("AFTER[" + Thread.currentThread().getName() + "]收到撤退命令,回家睡觉。。");
}
} catch (Exception e) {
e.printStackTrace();
}
}, "炮兵-" + i).start();
}
TimeUnit.SECONDS.sleep(3); //等待3秒钟
future.complete("cancel"); //给出了执行命令
}
}
BEFORE[炮兵-1]进入炮兵阵地,等待命令,准备开火。
BEFORE[炮兵-0]进入炮兵阵地,等待命令,准备开火。
BEFORE[炮兵-2]进入炮兵阵地,等待命令,准备开火。
BEFORE[炮兵-3]进入炮兵阵地,等待命令,准备开火。
//sleep 3 秒
AFTER[炮兵-1]收到撤退命令,回家睡觉。。
AFTER[炮兵-0]收到撤退命令,回家睡觉。。
AFTER[炮兵-2]收到撤退命令,回家睡觉。。
AFTER[炮兵-3]收到撤退命令,回家睡觉。。

该类的处理主要是建立在Future线程模型的基础之上的实现操作。

对于本类而言,除了以上的使用方式之外还可以采用异步的线程执行方式处理。在创建CompletableFuture类对象的时候还可以使用这个类之中提供的一种静态方法:

public static CompletableFuture<Void> runAsync(Runnable runnable)

范例:更换实现方式实现上述轰炸操作:

package com.itermis.concurrent;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; public class CompletableFutureDemoII {
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("[FUTURE]将军正在温柔乡里美梦了,等着将军睡醒开炮..");
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("[FUTURE]将军醒了,开始干活了..");
});
for (int i = 0; i < 4; i++) {
new Thread(() -> {
System.out.println("BEFORE[" + Thread.currentThread().getName() + "]进入炮兵阵地,等待命令,准备开火。");
try {
System.out.println("AFTER[" + Thread.currentThread().getName() + "]接收到命令,立刻开火,干死那个死胖子。。" + future.get());
} catch (Exception e) {
e.printStackTrace();
}
}, "炮兵-" + i).start();
}
}
}
[FUTURE]将军正在温柔乡里美梦了,等着将军睡醒开炮..
BEFORE[炮兵-1]进入炮兵阵地,等待命令,准备开火。
BEFORE[炮兵-0]进入炮兵阵地,等待命令,准备开火。
BEFORE[炮兵-2]进入炮兵阵地,等待命令,准备开火。
BEFORE[炮兵-3]进入炮兵阵地,等待命令,准备开火。
// sleep 3秒
[FUTURE]将军醒了,开始干活了..
AFTER[炮兵-2]接收到命令,立刻开火,干死那个死胖子。。null
AFTER[炮兵-0]接收到命令,立刻开火,干死那个死胖子。。null
AFTER[炮兵-3]接收到命令,立刻开火,干死那个死胖子。。null
AFTER[炮兵-1]接收到命令,立刻开火,干死那个死胖子。。null

CompletableFuture这个类最大的好处是提供有所有等待线程的执行触发点。

JUC——线程同步辅助工具类(Exchanger,CompletableFuture)的更多相关文章

  1. JUC——线程同步辅助工具类(Semaphore,CountDownLatch,CyclicBarrier)

    锁的机制从整体的运行转态来讲核心就是:阻塞,解除阻塞,但是如果仅仅是这点功能,那么JUC并不能称为一个优秀的线程开发框架,然而是因为在juc里面提供了大量方便的同步工具辅助类. Semaphore信号 ...

  2. Java并发编程系列-(2) 线程的并发工具类

    2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...

  3. Java线程的并发工具类

    Java线程的并发工具类. 一.fork/join 1. Fork-Join原理 在必要的情况下,将一个大任务,拆分(fork)成若干个小任务,然后再将一个个小任务的结果进行汇总(join). 适用场 ...

  4. 类型转换辅助工具类TypeCaseHelper

    package org.sakaiproject.util; import java.math.BigDecimal; import java.sql.Date; import java.sql.Ti ...

  5. 多线程状态与优先级、线程同步与Monitor类、死锁

    一.线程状态 二.线程优先级 三.初步尝试多线程 class Program { static void Main(string[] args) { while (true) { MessagePri ...

  6. JUC——线程同步锁(锁处理机制简介)

    锁处理机制简介 juc的开发框架解决的核心问题是并发访问和数据安全操作问题,当进行并发访问的时候如果对于锁的控制不当,就会造成死锁这样的阻塞问题. 为了解决这样的缺陷,juc里面重新针对于锁的概念进行 ...

  7. 【Java多线程】JUC包下的工具类CountDownLatch、CyclicBarrier和Semaphore

    前言 JUC中为了满足在并发编程中不同的需求,提供了几个工具类供我们使用,分别是CountDownLatch.CyclicBarrier和Semaphore,其原理都是使用了AQS来实现,下面分别进行 ...

  8. Java并发(十六):并发工具类——Exchanger

    Exchanger(交换者)是一个用于线程间协作的工具类.Exchanger用于进行线程间的数据交换.它提供一个同步点,在这个同步点两个线程可以交换彼此的数据.这两个线程通过exchange方法交换数 ...

  9. 线程同步之ManualResetEvent类的用法

    笔者的一台激光测厚设备的软件, 它有一个运动线程, 一个激光数据处理线程. 运动线程做的事就是由A点移动到B点, 然后再由B点移动回A点. 激光处理线程要做的事就是采集指定数量点的激光数据, 随着采集 ...

随机推荐

  1. 原生 JS 的 Base64 转码

    JavaScript 原生提供两个 Base64 相关的方法: btoa():任意值转为 Base64 编码 atob():Base64 编码转为原来的值 注意:这两个方法不适合非 ASCII 码的字 ...

  2. python处理数据(二)

    处理PDF文件 PyPDF2简介 作为 PDF 工具包构建的纯 python 库. 它可以:提取文档信息(标题,作者,... ...)一页一页地分割文件一页一页地合并文件裁剪页面将多个页面合并成一个页 ...

  3. IOS的滑动菜单(Sliding Menu)的具体写法(附代码)

    滑动菜单是一个很流行的IOS控件 先上效果图:        这里使用github的JTReveal框架来开发,链接是https://github.com/agassiyzh/JTRevealSide ...

  4. MySQL 导出远程服务器数据库 为 sql文件

    MySQL 导出远程服务器sql文件 mysqldump -h192.168.1.111 –P3306 -uroot -ppassword --default-character-set=utf8 t ...

  5. arcgis api for javascript本地部署加载地图

    最近开始学习arcgis api for javascript,发现一头雾水,决定记录下自己的学习过程. 一.下载arcgis api for js 4.2的library和jdk,具体安装包可以去官 ...

  6. 使用yii的layout,加入<?php echo $content; ?>这句话时,它会自动在子页面上面添加一个div包裹

    使用yii的layout,加入<?php echo $content; ?>这句话时,它会自动在子页面上面添加一个div包裹,而且div的id命名为id=content,这个和已有id重复 ...

  7. Java和Python安装和编译器使用

    java 一.安装jdk时第二次选择安装目录时,这是在安装jre,可以直接取消. 二.配置三个环境变量(在WIN7下) 右键我的电脑>属性>高级系统设置>环境变量>系统变量. ...

  8. Spring源码分析(九)解析默认标签中的自定义标签元素

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 到这里我们已经完成了分析默认标签的解析与提取过程,或许涉及的内容太多,我 ...

  9. Jmeter之断言

    Jmeter中的断言类似于LR中的检查点,是在请求的返回层面上加的一个判断机制.因为请求成功了,不代表结果就一定是对的,还要看返回(LR中亦如此,脚本回放没报错,不代表你的业务成功了,需要自己去相应的 ...

  10. [转载]AVFormatContext结构体详细分析

        AVFormatContext描述一个媒体文件或媒体流的构成和基本信息. 这是FFMpeg中最为基本的一个结构,是其他所有结构的根,是一个多媒体文件或流的根本抽象.其中nb_streams和s ...