import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 案例:服务员向原有空杯中不断倒水,消费者不断从原有装满水的杯中喝水。
* 当服务员倒满水和消费者喝完水时,两个杯子进行交换。一直这样周而复始。
* @author liuhongbo
*
*/
public class ExchargerTest {
static Exchanger<Cup> exchanger = new Exchanger<Cup>();
// 初始化时,100 只杯子都是满的
static Cup fullCup = new Cup(100);
static Cup emptyCup = new Cup(0);
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Waiter(3));
exec.execute(new Customer(6));
exec.shutdown();
}
static class Waiter implements Runnable {
int addSpeed = 1;
public Waiter(int addSpeed) {
this.addSpeed = addSpeed;
}
@Override
public void run() {
while (emptyCup != null) {
try {
// 如果都是空杯,
if (emptyCup.isFull()) {
// 当waiter把空杯装满水后,与Customer交换杯子
// exchange(emptyCup) 中参数的emptyCup是waiter装满水后的,把装满水后的emptyCup参数传递给cutomer线程。
// 并且返回cutomer线程中fullCup给waiter的emptyCup,这样达到交换本子的目的
emptyCup = exchanger.exchange(emptyCup);
} else {
// 有空杯,但不都是空杯,住空杯中加水
emptyCup.addWaterToCup(addSpeed);
System.out.println("Waiter add " + addSpeed + " and current capacity is " + emptyCup.capacity);
TimeUnit.SECONDS.sleep(1L);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Customer implements Runnable {
int drinkSpeed = 1;
public Customer(int drinkSpeed) {
this.drinkSpeed = drinkSpeed;
}
@Override
public void run() {
while (fullCup != null) {
try{
// 如果满杯是空的,则进行交换
if (fullCup.isEmpty()) {
fullCup = exchanger.exchange(fullCup);
System.out.println("Customer: " + fullCup.capacity);
} else {
// 如果满杯不全是空的,客户drink
fullCup.drinkFormCup(drinkSpeed);
System.out.println("Customer drink "+ drinkSpeed + " and current capacity is " + fullCup.capacity);
TimeUnit.SECONDS.sleep(2L);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Cup {
private int capacity = 0;
public Cup(int capacity) {
this.capacity = capacity;
}
public void addWaterToCup(int i) {
capacity += i;
capacity = capacity > 100 ? 100 : capacity;
}
public void drinkFormCup(int i) {
capacity -= i;
capacity = capacity < 0 ? 0 : capacity;
}
public boolean isFull() {
return capacity == 100 ? true : false;
}
public boolean isEmpty() {
return capacity == 0 ? true : false;
}
}
}
参考:http://conkeyn.iteye.com/blog/547370
分享到:
相关推荐
一个支持多线程的服务器框架,GeneralServer.java; 代理服务器,ProxyServer.java; telnet客户端,访问系统的telnet服务实质上是与telnet服务建立socket连接,默认的telnet服务的端口是23,TelnetClient.java; ...
7 一个支持多线程的服务器框架 13. 8 代理服务器 13. 9 Telnet客户端 13. 10 UDP编程 13. 11 聊天室服务器端 13. 12 聊天室客户端 13. 13 FTP客户端 第14章 数据库 14. 1 连接各种...
(1)如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率 (2)建模简单:通过使用线程可以讲复杂并且异步的工作流进一步分解成一组简单并且同步的工作流,每个工作流在一个单独的线程...
了解多线程所带来的安全风险.mp4 从线程的优先级看饥饿问题.mp4 从Java字节码的角度看线程安全性问题.mp4 synchronized保证线程安全的原理(理论层面).mp4 synchronized保证线程安全的原理(jvm层面).mp4 单例问题...
第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...
第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...
主要介绍java常用并发API,内容有: 基于String构建自己的锁管理器、 Collections构建不可修改的集合对象、 CopyOnWriteArrayList的应用场景、 可堵塞队列的功能及行为、 使用API实现压力测试、 CyclicBarrier与...
第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...
│ 高并发编程第一阶段05讲、采用多线程方式模拟银行排队叫号.mp4 │ 高并发编程第一阶段06讲、用Runnable接口将线程的逻辑执行单元从控制中抽取出来.mp4 │ 高并发编程第一阶段07讲、策略模式在Thread和Runnable...
│ 高并发编程第一阶段05讲、采用多线程方式模拟银行排队叫号.mp4 │ 高并发编程第一阶段06讲、用Runnable接口将线程的逻辑执行单元从控制中抽取出来.mp4 │ 高并发编程第一阶段07讲、策略模式在Thread和Runnable...