1. Java并发新构件之Exchanger
  2. JDK API

Exchaner 介绍

JDK API 解释

A synchronization point at which threads can pair and swap elements within pairs. Each thread presents some object on entry to the exchange method, matches with a partner thread, and receives its partner's object on return. An Exchanger may be viewed as a bidirectional form of a SynchronousQueue. Exchangers may be useful in applications such as genetic algorithms and pipeline designs.

Sample Usage: Here are the highlights of a class that uses an Exchanger to swap buffers between threads so that the thread filling the buffer gets a freshly emptied one when it needs it, handing off the filled one to the thread emptying the buffer.

我的翻译:

Exchanger可以看成是一个同步点,在这个同步点上两个线程可以结对并且交换各自的数据。每个线程都可传入某个对象给exchange方法,然后与对应的伙伴线程匹配,并且接收伙伴线程交换的某个对象。Exchanger可以看成是一个双向的SynchronousQueue队列。Exchanger可以被用在诸如遗传算法和通道设计等应用里。

张孝祥老师的比喻

Exchaner好比两个毒贩要进行交易,一手交money,一手交drug,不管是谁先到接头地点后,就处于等待状态;当另外一个方也达到接头地点(所谓到达接头地点,也就是到达了准备接头的状态)时,两者的数据就立即交换了,然后就可以各忙各的了。

我的理解

Exchanger的作用:两个结对线程之间交换数据的工具类。

简单使用

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by 58 on 2017-7-11.
*/
public class ExchangerTest1 { private static final Exchanger<String> exchanger = new Exchanger<>(); private static ExecutorService threadPool = Executors.newFixedThreadPool(3) ; public static void main(String[] args) { threadPool.execute(() -> {
String A = "A" ;
try {
System.out.println("A--->" + exchanger.exchange(A)) ;
} catch (Exception e) {
e.printStackTrace();
} });
threadPool.execute(() -> { String B = "B" ;
try {
System.out.println("B--->" + exchanger.exchange(B));
} catch (Exception e) {
e.printStackTrace();
} });
threadPool.execute(() -> { String C = "C" ;
try {
System.out.println("C--->" + exchanger.exchange(C));
} catch (Exception e) {
e.printStackTrace();
} });
}
}

应用场景

一个任务在创建对象,而这些对象的生产代价很高,另一个任务在消费这些对象。通过这种方式,可以有很多的对象被创建的同时被消费。


import java.util.List;
import java.util.concurrent.*; public class ExchangerDemo {
static int size = 10;
static int delay = 5; //秒
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
// 这个特定的List变体允许列表在被遍历的时候调用remove()方法,而不会抛出ConcurrentModifiedException异常
List<Fat> producerList = new CopyOnWriteArrayList<>();
List<Fat> consumerList = new CopyOnWriteArrayList<>();
Exchanger<List<Fat>> exchanger = new Exchanger<>();
exec.execute(new ExchangerProducer(exchanger, producerList));
exec.execute(new ExchangerConsumer(exchanger, consumerList));
TimeUnit.SECONDS.sleep(delay);
exec.shutdownNow();
}
} class ExchangerProducer implements Runnable {
private List<Fat> holder;
private Exchanger<List<Fat>> exchanger;
public ExchangerProducer(Exchanger<List<Fat>> exchanger, List<Fat> holder) {
this.exchanger = exchanger;
this.holder = holder;
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
//生产对象
for (int i = 0;i < ExchangerDemo.size; i++) {
holder.add(new Fat());
}
//生产完毕后 等待进行交换
holder = exchanger.exchange(holder);
}
} catch (InterruptedException e) {
}
System.out.println("Producer stopped.");
}
} class ExchangerConsumer implements Runnable {
private List<Fat> holder;
private Exchanger<List<Fat>> exchanger;
private volatile Fat value;
private static int num = 0;
public ExchangerConsumer(Exchanger<List<Fat>> exchanger, List<Fat> holder) {
this.exchanger = exchanger;
this.holder = holder;
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
//等待交换
holder = exchanger.exchange(holder);
//取到生产者生产的数据 开始模拟消费的场景
for (Fat x : holder) {
num ++;
value = x;
//消费 在循环内删除元素,这对于CopyOnWriteArrayList是没有问题的
holder.remove(x);
}
if (num % 10000 == 0) {
System.out.println("Exchanged count=" + num);
}
}
} catch (InterruptedException e) { }
System.out.println("Consumer stopped. Final value: " + value);
}
} class Fat {
private volatile double d;
private static int counter = 1;
private final int id = counter++;
public Fat() {
//执行一段耗时的操作
for (int i = 1; i<10000; i++) {
d += (Math.PI + Math.E) / (double)i;
}
}
public String toString() {return "Fat id=" + id;}
}

Exchanger学习的更多相关文章

  1. Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger

    本文将要介绍的内容都是Java5中的新特性,一个是倒计时记数器---CountDownLatch,另一个是用于线程间数据交换的Exchanger. 一.CountDownLatch 1.什么是Coun ...

  2. [转载] java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger

    转载自http://janeky.iteye.com/blog/770393 ------------------------------------------------------------- ...

  3. 并发编程学习笔记(10)----并发工具类CyclicBarrier、Semaphore和Exchanger类的使用和原理

    在jdk中,为并发编程提供了CyclicBarrier(栅栏),CountDownLatch(闭锁),Semaphore(信号量),Exchanger(数据交换)等工具类,我们在前面的学习中已经学习并 ...

  4. 学习了解 Exchanger - 实现生产者消费者模型

    例子很简单 Exchanger可以理解为消息队列或者说是一个通信管道,从一边拿到消息,另外一边进行消费. 不过这个是同步实现的,消费者在exchange之前,生产者一直处于等待状态,而不是一直生产. ...

  5. java Concurrent包学习笔记(六):Exchanger

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

  6. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  7. JAVA并发编程J.U.C学习总结

    前言 学习了一段时间J.U.C,打算做个小结,个人感觉总结还是非常重要,要不然总感觉知识点零零散散的. 有错误也欢迎指正,大家共同进步: 另外,转载请注明链接,写篇文章不容易啊,http://www. ...

  8. Java核心编程快速学习

    Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示. 反射reflect是理解Java语言工作原理的基础,Java编译器首先需要将我们编写的 ...

  9. Java并发编程深入学习

    上周的面试中,被问及了几个并发开发的问题,自己回答的都不是很系统和全面,可以说是"头皮发麻",哈哈.因此果断购入<Java并发编程的艺术>一书,该书内容主要是对ifev ...

随机推荐

  1. 洛谷4245:【模板】任意模数NTT——题解

    https://www.luogu.org/problemnew/show/P4245 给两个多项式,求其乘积,每个系数对p取模. 参考: 代码与部分理解参考https://www.luogu.org ...

  2. ACM数学

     1.burnside定理,polya计数法 这个专题我单独写了个小结,大家可以简单参考一下:polya 计数法,burnside定理小结 2.置换,置换的运算 置换的概念还是比较好理解的,< ...

  3. bzoj3680: 吊打XXX(模拟退火)

    题目要求 最小(dis表示绳结到点i的距离),就是个广义费马点的题,模拟退火裸题QAQ 模拟退火就是优化后的爬山算法,一开始先随机一个平均点,接下来如果随机到的点比当前点劣,温度比较高的话也有几率跳过 ...

  4. ContestHunter暑假欢乐赛 SRM 09(TJM大傻逼选手再创佳绩)

    T1 f[i]为前i页最少被撕几页,用二分转移就行了,答案为ans=min(f[i]+(n-i)); 不知道为什么写挂了嗯 二分的l初始应该是0 T2 数位DP f[i][1/0][1/0][1/0] ...

  5. Nginx反向代理两个tomcat服务器

    第一步,在Linux上安装两个tomcat,修改好端口号后,启动起来. 第二步,配置本地的DNS解析,即修改host文件: 第三步,配置Nginx配置文件 反向代理的配置虚拟主机配置差不多也要配置虚拟 ...

  6. Codeforces Round #394 (Div. 2)A水 B暴力 C暴力 D二分 E dfs

    A. Dasha and Stairs time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  7. maven中用yuicompressor和closure-compiler对js、css文件进行压缩

    转载自:http://matychen.iteye.com/blog/1477350 项目采用maven构建的时候,需要压缩js,css等,网上找了相关资料,自己综合了下-  直接放代码: <! ...

  8. JavaScript中检测数组的几种方式

    检测一个对象是否为数组的方式有: Array.isArray()          // true或false(es5) toString.call([]);       // [object Arr ...

  9. tortoise svn冲突解决

    Tortoiese svn 冲突解决 当文件被别人修改并提交到SVN服务器后,如果自己本地的文件没有被更新为最新的版本,而且已经做了修改,这时候提交将会被成功,系统会提示你的版本已经过期,并要求你先进 ...

  10. 确保web安全的https、确认访问用户身份的认证(第七章、第八章)

    第七章 确保web安全的https 1.http的缺点: (1)通信使用明文,内容可能会被窃听 (2)不验证通信方的身份,因此有可能遭遇伪装 (3)无法证明报文的完整性,因此有可能已遭篡改. 2.通信 ...