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. php 分享一个object(stdclass)转数组的函数

    经常调用一个借口之后 返回的内容是json串,利用php函数json_decode() 解析json串之后得到的 数据类型为object(stdclass) 这是一个对象,要取其中的内容也可以 取得, ...

  2. Hibernate核心对象

    1.Configuration Configuration 类负责管理Hibernate的配置信息.它包括如下内容: Hibernate运行的底层信息:数据库的URL.用户名.密码.JDBC驱动类,数 ...

  3. Ceph块存储介绍

    1. 块存储是什么 块存储简称RBD(RADOS Block Device),是一种有序的字节序块,也是在Ceph三大存储类型中最为常用的存储方式 ,Ceph的块存储是基于RADOS的,因此它也借助R ...

  4. JavaScript设计模式—工厂模式

    工厂模式介绍 将new操作符单独进行封装,遇到new时,就要考虑是否该使用工厂模式 举一个生活当中的示例: 你要去购买汉堡,直接点餐,取餐,不会自己动手做,商店要“封装” 做汉堡的工作,做好直接给购买 ...

  5. Hive学习之路 (十六)Hive分析窗口函数(四) LAG、LEAD、FIRST_VALUE和LAST_VALUE

    数据准备 数据格式 cookie4.txt cookie1, ::,url2 cookie1, ::,url1 cookie1, ::,1url3 cookie1, ::,url6 cookie1, ...

  6. git问题整理

    //1.git常用命令,git的branch 2.git的原理 //4.怎么同步到本地仓库,怎么传到远程仓库 //3.git中 rebase 和 merge的区别 5.git的使用,讲一下? //4. ...

  7. Mysql 多实例实施步骤

    基本理论:利用同一套安装程序,不同配置文件,不同启动程序,不同数据目录.有公用资源,也有私有资源. 实现步骤: 1.正常安装mysql,二进制安装或者编译安装. 2.创建mysql多实例总目录,总目录 ...

  8. ZOJ 2017 Quoit Design 经典分治!!! 最近点对问题

    Quoit Design Time Limit: 5 Seconds      Memory Limit: 32768 KB Have you ever played quoit in a playg ...

  9. linux iSCSI target/initiator配置

    linux iSCSI target配置全过程一:Install iSCSI target for Linux1,操作系统:[root@rac2 ~]# cat /etc/issueEnterpris ...

  10. 记Macbook Pro配合FT232使用PN532模块

    0x00实话. 被自己傻到 在linux下使用 libusb + libnfc 这两个库就可以配合串口直接使用pn532模块 当时配置文件是写在 /etc/nfc 目录下的 而我在OS X 下居然也想 ...