[笔记][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语言的特性,基础概念和标准命令. 一. ...
随机推荐
- Linux上用Docker部署Net Core项目
前提:本地配置好Docker环境1.构建Net Core镜像 docker pull microsoft/dotnet 2.新建一个DockerFile文件并填充内容 #基于 `microsoft/d ...
- React Native 系列(八)
前言 本系列是基于React Native版本号0.44.3写的.我们都知道,一个App不可能只有一个不变的界面,而是通过多个界面间的跳转来呈现不同的内容.那么这篇文章将介绍RN中的导航. 导航 什么 ...
- dcoker常用命令
记录一下常用的命令 docker run -t -i xxxx /bin/bash 运行容器的交互会话shell docker start xxxx 启动容器 docker stop xxxx 停止 ...
- Arab Collegiate Programming Contest 2012 J- Math Homework
思路:由于只有1-6这几个数,而这几个数的最小公倍数是60,所以只需要求出60以内有多少满足条件的数即可. 再就是求出对于给定的n,求出60的倍数.然后就是怎样求的问题了. 首先可以写成如下形式: ...
- poj 2001 trie
第一道trie 还需要写题来建立自己的代码习惯. #include <cstdio> #include <vector> #include <algorithm> ...
- bzoj 1674: [Usaco2005]Part Acquisition -- dijkstra(堆优化)
1674: [Usaco2005]Part Acquisition Time Limit: 5 Sec Memory Limit: 64 MB Description The cows have b ...
- ACM -- 算法小结(十)素数的两种打表法
素数的两种打表法 下面介绍两种素数打表法,由于是两年前留下的笔记,所以没有原创链接~~ @_@!! 第一种疯狂打表法: #include<stdio.h> #include<math ...
- Spring---介绍
核心容器:Core.Beans.Context.EL模块 1. Core模块:封装了框架依赖的最底层部分,包括访问资源.类型转换及一些常用工具类 2. Beans模块:提供了框架的基础 ...
- PAT甲级1026. Table Tennis
PAT甲级1026. Table Tennis 题意: 乒乓球俱乐部有N张桌子供公众使用.表的编号从1到N.对于任何一对玩家,如果有一些表在到达时打开,它们将被分配给具有最小数字的可用表.如果所有的表 ...
- TortoiseSVN 修改密码
在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了. 不过,如果 ...