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. c++程序员学习go

    作为一个c++程序员学习go编程的笔记.首先声明本人文笔太差,当你阅读一点觉得实在无法阅读下去时请移步. 下载安装go,安装完毕后会增加系统环境变量path内容指定go程序所在目录,可以打开cmd输入 ...

  2. 【ORACLE】 安装需要注意的问题(一)

    安装ORACLE虽然不是很难,但是有时候很容易因为一些小细节导致安装失败,浪费大量的时间. 这里总结一下安装ORACLE的时候需要注意的问题,以及解决的办法 问题1:系统先决条件检查 正在检查操作系统 ...

  3. Eclipse Debug Daemon Thread

    Daemon Thread ["http-bio-8080"-exec-2] (Suspended (exception RuntimeException)) ThreadPool ...

  4. 记一次webservice的超时时间设置

    一次项目组中需要控制超时时间,前期习惯用CXF实现,熟悉的才是最好的.所以这次依然想用CXF实现. 实现的方式代码如下: static{ String fvpWebserviceUrl = Prope ...

  5. 简单的Windows 服务的安装和卸载

    步骤: 1.运行--〉cmd:打开cmd命令框 2.在命令行里定位到InstallUtil.exe所在的位置 InstallUtil.exe 默认的安装位置是在C:/Windows/Microsoft ...

  6. Docker删除/停止容器

    应用场景:某个相关的业务需要重启,容器太多了,一个一个通过命令行来关闭太麻烦了,直接一条命令直接搞定. 命令如下: $ docker ps // 查看所有正在运行容器 $ docker stop co ...

  7. win10下安装Jenkins

    Jenkins是一个基于java的持续集成工具,开源项目.用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能.随着近几年docker技术的成熟和应用,很多公司开始大量尝试 ...

  8. P1070 道路游戏

    题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 n 个机器人工厂编 ...

  9. selenium和PhantomJS的安装

    针对w10系统 selenium安装 pip install selenium 默认安装的是3.x版本,但是3.x版本不支持PhantomJS,所以要安装2.x版本 pip install selen ...

  10. css布局中关于 块状元素和行内元素的区分

    这两天在准备实习的面试和笔试,准备复习一下这些基础的概念,避免自己处于一种仅脑袋理解嘴巴不能表述出来的状态. 块状元素和行内元素的概念是在css页面布局这个地方出现.主要是将html标签按照一定的特性 ...