[笔记][Java7并发编程实战手冊]3.8 并发任务间的数据交换Exchanger
简单介绍
Exchanger 是一个同步辅助类。用于两个并发线程之间在一个同步点进行数据交换。
同意两个线程在某一个点进行数据交换。
本章exchanger 使用心得总结
- 两个线程必须使用同一个Exchanger对象,且仅仅能是两个线程间的数据交换
- exchanger.exchange(v)的时候,当前线程会被堵塞,直到还有一个线程运行该方法,同一时候完成数据的交换
- 相似这样的数据交换的,生产者线程一定要先生产数据。再交换数据,消费者线程一定要先交换数据,再消费数据,否则会出现少消费数据的现象
演示样例
场景描写叙述:一对一的 生产者和消费者。生产者每次生产5个商品,然后消费者把空的商品容器和生产者交换。
/**
* Created by zhuqiang on 2015/8/23 0023.
*/
public class Client {
public static void main(String[] args) {
Exchanger<ArrayList<String>> exchanger = new Exchanger<ArrayList<String>>();
new Thread(new Producer(exchanger)).start();
new Thread(new Consumer(exchanger)).start();
}
}
// 生产者
class Producer implements Runnable {
private ArrayList<String> goods = new ArrayList<String>(); //商品容器
private Exchanger<ArrayList<String>> exchanger = new Exchanger<ArrayList<String>>();
public Producer(Exchanger<ArrayList<String>> exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) { //生产3次
System.out.println("------------------------生产者生产第 " + i + "次");
for (int j = 0; j < 3; j++) { //每次生产3个商品
String e = (long) (Math.random() * 1000) + "";
goods.add(e);
System.out.println("生产了商品:" + e);
}
try {
goods = exchanger.exchange(goods); //交换数据
System.out.println("生产者:数据交换完成:获得交换的商品容器大小:" + goods.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//消费者
class Consumer implements Runnable {
private ArrayList<String> goods = new ArrayList<String>(); //商品容器
private Exchanger<ArrayList<String>> exchanger = new Exchanger<ArrayList<String>>();
public Consumer(Exchanger<ArrayList<String>> exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) { //消费3次
try {
goods = exchanger.exchange(goods); //交换数据
System.out.println("消费者:数据交换完成:获得交换的商品容器大小:" + goods.size());
// 消费商品
Iterator<String> it = goods.iterator();
if (goods.size() > 0) {
System.out.println("*********************消费者消费第 " + i + "次");
while (it.hasNext()) {
String next = it.next();
System.out.println("消费了商品:" + next);
it.remove(); //移除消费了的商品
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
某一次运行结果:
------------------------生产者生产第 0次
生产了商品:727
生产了商品:671
生产了商品:345
生产者:数据交换完成:获得交换的商品容器大小:0
------------------------生产者生产第 1次
生产了商品:67
生产了商品:466
生产了商品:207
消费者:数据交换完成:获得交换的商品容器大小:3
*********************消费者消费第 0次
消费了商品:727
消费了商品:671
消费了商品:345
消费者:数据交换完成:获得交换的商品容器大小:3
生产者:数据交换完成:获得交换的商品容器大小:0
------------------------生产者生产第 2次
*********************消费者消费第 1次
消费了商品:67
消费了商品:466
消费了商品:207
生产了商品:38
生产了商品:355
生产了商品:24
生产者:数据交换完成:获得交换的商品容器大小:0
消费者:数据交换完成:获得交换的商品容器大小:3
*********************消费者消费第 2次
消费了商品:38
消费了商品:355
消费了商品:24
结果说明
看上面的结果,能够发现两个线程是并行运行的,仅仅有在交换的时候,交换数据同步点。
是不是认为看着不明所以。这样看
————————生产者生产第 0次
生产了商品:727
第0次生产商品是 727。
***********消费者消费第 0次
消费了商品:727
第0次消费的也是727, 这就说明了。两个线程之间交换数据是我们想要的结果。
假如:我们把 以下的运行顺序调换下,让consumer在前。结果你发现还是先生产后消费。
这个是为什么呢?
new Thread(new Producer(exchanger)).start();
new Thread(new Consumer(exchanger)).start();
是由于:
1. 从java内存模型角度来说。上面两行代码没有数据依赖性(在实际运行的时候他们的顺序不一定是谁先谁后)
2. 原因就出如今exchanger.exchange(v)方法。就算是消费者先运行,细致看代码。消费者会先运行exchanger.exchange(v)方法。假设之前没有线程运行该方法,那么消费者则会休眠等待生产者运行该方法。
[笔记][Java7并发编程实战手冊]3.8 并发任务间的数据交换Exchanger的更多相关文章
- [笔记][Java7并发编程实战手冊]系列文件夹
推荐学习多线程之前要看的书. [笔记][思维导图]读深入理解JAVA内存模型整理的思维导图文章里面的思维导图或则相应的书籍.去看一遍. 能理解为什么并发编程就会出现故障. Java7并发编程实战手冊 ...
- [笔记][Java7并发编程实战手冊]3.4 等待多个并发事件的完毕CountDownLatch倒计数闭锁
[笔记][Java7并发编程实战手冊]系列文件夹 简单介绍 本文学习CountDownLatch 倒计数闭锁. 本人英文不好.靠机器翻译,然后有一段非常形象的描写叙述,让我把它叫为倒计数 用给定的计数 ...
- 那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结
<Java并发编程实战>和<Java并发编程的艺术> Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用 ...
- 【Java并发编程实战】—–synchronized
在我们的实际应用其中可能常常会遇到这样一个场景:多个线程读或者.写相同的数据,訪问相同的文件等等.对于这样的情况假设我们不加以控制,是非常easy导致错误的. 在java中,为了解决问题,引入临界区概 ...
- 《java并发编程实战》笔记
<java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为: Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...
- 《 .NET并发编程实战》一书中的节流为什么不翻译成限流
有读者问,为什么< .NET并发编程实战>一书中的节流为什么不翻译成限流? 这个问题问得十分好!毕竟“限流”这个词名气很大,耳熟能详,知名度比“节流”大多了. 首先,节流的原词Thrott ...
- 《Java7并发编程实战手册》读书笔记
一.线程管理 1.线程的创建和运行 创建线程的2种方式: 继承Thread类,并覆盖run()方法 创建一个实现Runnable接口的类.使用带参数的Thread构造器来创建Thread对象 每个Ja ...
- 《Go并发编程实战》读书笔记-语法概览
<Go并发编程实战>读书笔记-语法概览 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客我们会快速浏览一下Go的语法,内容涉及基本构成要素(比如标识符,关键字,子 ...
- 《Go并发编程实战》读书笔记-初识Go语言
<Go并发编程实战>读书笔记-初识Go语言 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在讲解怎样用Go语言之前,我们先介绍Go语言的特性,基础概念和标准命令. 一. ...
随机推荐
- RabbitMQ (十六) 消息队列的应用场景 (转)
原贴 : http://blog.csdn.net/cws1214/article/details/52922267 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题 ...
- Unity Shader 之 uv动画
Unity 动画 Unity Shader 内置时间变量 引入时间变量 名称 类型 描述 _Time float4 t是自该场景加载开始所经过的时间,4个分量分别是(t/20, t, 2t, 3t) ...
- 洛谷 P1115 最大子段和
P1115 最大子段和 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入输出格式 输入格式: 输入文件maxsum1.in的第一行是一个正整数N,表示了序列的长度. 第2行包含N ...
- luoguP4115 QTREE4 链分治
具体看$qzc$论文吧......陈年老物了...... 主要注意每个链头一棵线段树而不是一棵全局线段树 修改操作写完就是正确的,反而是初始化调了好一会...... 跑的还是很快的,有些地方没优化常数 ...
- 【二分答案】BZOJ2016-Chocolate Eating
[题目大意] n块巧克力,每次吃可以增加ai点快乐,每天早晨睡觉起来快乐值会减半,求如何使d天睡觉前的最小快乐值最大. [思路] 二分每天的最小快乐值,只要没有达到快乐值就继续吃. 不知道为什么了WA ...
- 在centos6.0上通过nginx远程执行shell
nginx本身不支持直接调用shell脚本,我们可以通过安装fastcgi程序,让nginx把调用shell的http请求交给fastcgi程序去处理,然后nginx 再将结果返回给用户方式间接调用s ...
- PHP 日期的加减
- linux命令: Netstat
在Internet RFC标准中,Netstat的定义是: Netstat是在内核中访问网络及相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告. Netstat是控 ...
- Python,JAVA中子类的构造函数与父类构造函数的关系
Python: 子类不重载.覆盖父类的构造函数(子类不自己定义构造函数),则构造子类时会调用父类构造函数 若子类覆盖了父类的构造函数,则构造子类时不执行父类的构造函数,但仍继承了父类,如需调用父类构造 ...
- Codeforces Round #FF (Div. 1) B. DZY Loves Modification
枚举行取了多少次,如行取了i次,列就取了k-i次,假设行列单独贪心考虑然后相加,那么有i*(k-i)个交点是多出来的:dpr[i]+dpc[k-i]-i*(k-i)*p 枚举i取最大值.... B. ...