java Thread学习(线程间协作)
线程件协作
线程之间除了使用锁同步两个任务的行为外,还需要进行协作,例如任务A必须在B完成后才能执行。
wait()和notify()/notifyAll()
wait()会去等待外部信号,并且在等待时将自身挂起。等待notify()信号唤醒。
wait()挂起的时候,会释放对象锁,这导致其他的线程可以使用synchronized方法,产生改变,将被挂起的线程唤醒。
- wait()/wait(t):使用wait将挂起线程,可以无限等待,也可以指定时间,超时后恢复执行
- 可以通过notify()/notifyAll(),或者时间到期后
注意:
- 这些方法都是针对于对象来说的,wait()释放对象锁,挂起当前的线程。notify()在执行完同步代码块后释放锁,然后所有wait对象锁的线程中随机唤醒一个
- wait/notify/notifyAll都是Object中的方法。但是只能在同步控制方法或者同步块中使用。否则运行报错IIIegalMonitorStateException。
- notify()唤醒一个线程/notifyAll()唤醒所有对象锁。notify()有可能产生死锁。所以尽量使用notifyAll()
使用另一个对象唤醒自身时,需要先获取对象锁。例如
synchronized(x) {x.notigyAll(); }
举例:给车打蜡+抛光,打蜡后才能抛光,抛光完成后继续打蜡
class Car{private boolean waxOn = false;public synchronized void waxed() {waxOn = true;/*** do something*/notifyAll();}public synchronized void buffed() {waxOn = false;/*** do ...*/notifyAll();}public synchronized void waitForWaxing() throws InterruptedException {while(waxOn == false) {//唤醒是随机的,所以可能依然需要waitwait();}}public synchronized void waitForBuffing() throws InterruptedException {while(waxOn == true) {wait();}} } class WaxOn implements Runnable{private Car car;public WaxOn(Car car) {this.car = car;}public void run() {try{while(!Thread.interrupted()) {System.out.println("Wax On!");car.waxed();//先执行了一次操作,后判断???car.waitForBuffing();}} catch(InterruptedException e) {System.out.println("Exiting via interrupt");}System.out.println("Ending wax On task");} } class WaxOff implements Runnable {private Car car;public WaxOff(Car car) {this.car = car;}public void run() {try{while(!Thread.interrupted()) {System.out.println("Wax Off");car.buffed();car.waitForWaxing();}} catch(InterruptedException e) {System.out.println("Exiting via interrupt");}System.out.println("Ending wax Off task");} } public class WaxOMatic {public static void main(String[] args) throws InterruptedException {Car car = new Car();ExecutorService service = Executors.newCachedThreadPool();service.execute(new WaxOn(car));service.execute(new WaxOff(car));TimeUnit.SECONDS.sleep(5);service.shutdownNow();} }
Condition对象
在java.util.concurrent类库中包含了Condition类。await()和signal()/signalAll()也可以完成协调的作用。
java
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();//通过使用一个锁来获得Condition
condition.await();
condition.signal();
condition.signalAll();
注意:
- 每一个Lock都应该在try-finally中,保证任何情况都可以释放锁。
- 任务使用await()或者signal()前必须进行加锁。
notify()/notifyAll()
notify()仅唤醒一个线程,可能出现死锁。举例生产者P-消费者C问题。引用自http://blog.csdn.net/tayanxunhua/article/details/20998809
第一步:P1放入一个对象到buffer中;
第二步:P2试图put一个对象,此时buf中已经有一个了,所以wait
第三步:P3试图put一个对象,仍然wait
第四步:
- C1试图从buf中获得一个对象;
- C2试图从buf中获得一个对象,但是挡在了get方法外面
- C3试图从buf中获得一个对象,同样挡在了get方法外面
第五步:C1执行完get方法,执行notify,退出方法。notify唤醒了P2,但是C2在P2唤醒之前先进入了get方法,所以P2必须再次获得锁,P2被挡在了put方法的外面,C2循环检查buf大小,在buf中没有对象,所以只能wait;C3在C2之后,P2之前进入了方法,由于buf中没有对象,所以也wait;
第六步:现在,有P3,C2,C3在waiting;最后P2获得了锁,在buf中放入了一个对象,执行notify,退出put方法;
第七步:notify唤醒P3;P3检查循环条件,在buf中已经有了一个对象,所以wait;现在没有线程能够notify了,三个线程就会处于死锁状态。
生产者-消费者
饭店呢的一个示例:厨师需要做饭,服务员需要端菜。饭店包含了厨师,服务员,食物。厨师、服务员、食物都包含饭店,通过饭店操纵其他的对象。
```java
class Meal {private final int orderNum;public Meal(int orderNum) {this.orderNum = orderNum;}public String toString(){return "Meal: " + orderNum;}
}
class WaitPerson implements Runnable{private Restaurant restaurant;public WaitPerson(Restaurant restaurant) {this.restaurant = restaurant;}public void run() {try {while(!Thread.interrupted()) {synchronized (this) {while(restaurant.getMeal() == null) {wait();}}System.out.println("WaitPerson got " + restaurant.getMeal());synchronized (restaurant.getChef()) {while(restaurant.getMeal() != null) {restaurant.setMeal(null);restaurant.getChef().notifyAll();}}}} catch(InterruptedException e) {System.out.println("WaitPerson Interrupted");}}
}
class Chef implements Runnable {private Restaurant restaurant;private volatile int count = 0;public Chef(Restaurant restaurant) {this.restaurant = restaurant;}public void run() {try {while(!Thread.interrupted()) {synchronized(this) {while(restaurant.getMeal() != null) {wait();}}if(++count == 10) {System.out.println("Out of food, closing");restaurant.getExecutorService().shutdownNow();}System.out.println("Order up!");synchronized (restaurant.getWaitPerson()) {restaurant.setMeal(new Meal(count));restaurant.getWaitPerson().notifyAll();}TimeUnit.MILLISECONDS.sleep(100);}} catch(InterruptedException e) {System.out.println("Chef Interrupted");}}
}
public class Restaurant {private Chef chef;private WaitPerson waitPerson;private Meal meal;private ExecutorService service;public Restaurant() {service = Executors.newCachedThreadPool();chef = new Chef(this);waitPerson = new WaitPerson(this);service.execute(chef);service.execute(waitPerson);}public static void main(String[] args) {new Restaurant();}public void setChef(Chef chef) {this.chef = chef;}public Chef getChef() {return chef;}public void setWaitPerson(WaitPerson waitPerson) {this.waitPerson = waitPerson;}public WaitPerson getWaitPerson() {return waitPerson;}public void setMeal(Meal meal) {this.meal = meal;}public Meal getMeal() {return meal;}public void setExecutorService(ExecutorService service) {this.service = service;}public ExecutorService getExecutorService() {return service;}
}
```
生产者-消费者与队列
同步队列:java.util.concurrent.BlockingQueue接口提供了同步队列,如果消费者从队列中获取对象,而且队列中为空,那么线程就会被挂起。
- LinkedBlockingQueue:不限定队列大小
- ArrayBlockingQueue:需要限定队列的大小
- SynchronizedBlockingQueue:默认为1的队列
常用方法 | 应用 |
---|---|
add(Obj) | 放入一个Object,成功返回true,否则返回异常 |
offer(Obj) | 放入一个Object,成功返回true,否则返回false |
put(Obj) | 放入一个Object,成功返回true,否则挂起线程,有空间时继续 |
poll(Obj) | 取出队首的元素,如果不能立即取出,则等待指定时间,取不到返回null |
take(Obj) | 取出队首的元素,如果不能立即取出,挂起线程,等待存在数据后再继续 |
```java
class Toast {public enum Status { DRY, BUTTERED, JAMMED}public Status status = Status.DRY;public final int id;public Toast(int id) { this.id = id; }public void butter() { status = Status.BUTTERED; }public void jam() { status = Status.JAMMED; }public Status getStatus() { return status; }public int getId() { return id; }public String toString() {return "Toast " + id + ": " + status;}
}
class ToastQueue extends LinkedBlockingQueue<Toast> {}
class Toaster implements Runnable {private ToastQueue dryQueue;private int count = 0;public Toaster(ToastQueue dryQueue) {this.dryQueue = dryQueue;}public void run() {try {while(!Thread.interrupted()) {TimeUnit.MILLISECONDS.sleep(100);Toast t = new Toast(++count);System.out.println("Toaster: " + t);dryQueue.put(t);}} catch(InterruptedException e) {System.out.println("Toaster interrupted");}}
}
class Butterer implements Runnable {private ToastQueue dryQueue, butteredQueue;public Butterer(ToastQueue dryQueue, ToastQueue butteredQueue) {this.dryQueue = dryQueue;this.butteredQueue = butteredQueue;}public void run() {try {while(!Thread.interrupted()) {Toast t = dryQueue.take();t.butter();System.out.println("Butter: " + t);butteredQueue.put(t);}} catch(InterruptedException e) {System.out.println("Butterer Interrupted");}}
}
class Jammer implements Runnable {private ToastQueue butteredQueue, finishedQueue;public Jammer(ToastQueue butteredQueue, ToastQueue finishedQueue) {this.butteredQueue = butteredQueue;this.finishedQueue = finishedQueue;}public void run() {try {while(!Thread.interrupted()) {Toast t = butteredQueue.take();t.jam();System.out.println("Jammer: " + t);finishedQueue.put(t);}} catch(InterruptedException e) {System.out.println("Butterer Interrupted");}}
}
public class ToastOMatic {public static void main(String[] args) throws InterruptedException {ToastQueue dryQueue = new ToastQueue();ToastQueue butteredQueue = new ToastQueue();ToastQueue finishedQueue = new ToastQueue();ExecutorService service = Executors.newCachedThreadPool();service.execute(new Toaster(dryQueue));service.execute(new Butterer(dryQueue, butteredQueue));service.execute(new Jammer(butteredQueue, finishedQueue));TimeUnit.SECONDS.sleep(3);service.shutdownNow();}
}
```
管道输入/输出
使用PipedReader,PipedWriter创建一个管道,当PipedReader读不到数据时,管道就会自动阻塞(允许不同的任务从同一个管道中读取)
```java
class Sender implements Runnable {private Random rand = new Random(47);private PipedWriter out = new PipedWriter();public void run() {try {while(true) {for(char c = 'A'; c <= 'Z'; c++) {out.write(c);TimeUnit.MILLISECONDS.sleep(rand.nextInt(500));}}} catch(IOException e) {System.out.println("Sender write exception\n" + e);} catch(InterruptedException e) {System.out.println("Sender write exception\n" + e);}}public PipedWriter getPipedWriter() {return out;}
}
class Receiver implements Runnable {private PipedReader in;public Receiver(Sender s) throws IOException {in = new PipedReader(s.getPipedWriter());}public void run() {try {while(true) {System.out.println("Read: " + (char)in.read());}} catch (IOException e) {System.out.println("Receiver read exception\n" + e);}}
}
public class PipedIO {public static void main(String[] args) throws Exception {Sender sender = new Sender();Receiver receiver = new Receiver(sender);ExecutorService service = Executors.newCachedThreadPool();service.execute(sender);service.execute(receiver);TimeUnit.SECONDS.sleep(4);service.shutdownNow();}
}
```
java Thread学习(线程间协作)相关推荐
- Java并发编程—线程间协作方式wait()、notify()、notifyAll()和Condition
原文作者:Matrix海 子 原文地址:Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 目录 一.wait().notify()和notifyA ...
- Java多线程之线程间协作 notify与wait的使用
(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景 Java多线程操作运用很广,特别是在android程序方面.线程异步协作是多线程操作的难点也是关键,也 ...
- 19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...
- JAVA线程间协作:wait.notify.notifyAll
欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...
- 线程间协作的两种方式:wait、notify、notifyAll和Condition
转载自 线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当 ...
- java多线程与线程间通信
转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...
- Java多线程:线程间通信方式
文章目录 Java线程通信 wait().notify().notifyAll() API说明 实现原理 代码实现 await().signal().signalAll() API说明 实现原理 代码 ...
- 【java笔记】线程间通信(2):生产者和消费者案例分析
[java笔记]线程间通信(1):等待唤醒机制_m0_52043808的博客-CSDN博客 类: 资源类:包子类:皮,馅,有无 生产者: 包子铺类(线程类)(继承Thread) 设置线程任务(run) ...
- java多线程方式轮询,深入理解JAVA多线程之线程间的通信方式
一,介绍 本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信,故摘抄了书中的一些示例代码. 二,线程间的通信方式 ①同步 这里讲的同步是指多个线程通过sy ...
最新文章
- 温度转换的python程序_Python通过小实例入门学习---1.0(温度转换)
- ubuntu14.04安装完ros后常用的其他安装
- E:VUE 插件 开发与使用 (一)
- 【Java】强软弱虚四种引用,弱引用在ThreadLocal中的应用
- 利用EVC快速开发WINCE5.0的流驱动(转载)
- [翻译]超炫列表动画的实现
- MATLAB--求解矩阵方程
- nginx部署前端代码 负载均衡
- 怎么用手机修改图片大小?在线修改图片的方法?
- spring 实现小程序抖音去水印后台
- JavaScript中的动画效果
- 台计算机的本地打印机 并且,三台电脑,怎么共用一台打印机?
- zhang 快速并行细化方法_Zhang快速并行细化算法.docx
- 阿里云天池机器学习训练营(Day7, Day8):机器学习算法(三):K近邻(k-nearest neighbors)初探
- 无限级树状图html5,无限树状列表的实现
- 软件架构入门及分类——微内核架构
- 2020年“信创”火了!一文看懂什么是信创
- Angular学习笔记64:使用Render2安全操作DOM元素
- 网络系统设计过程中,物理网络设计阶段的任务是(70)。【答案】A
- 计算机原理学习(序)
热门文章
- php 清除缓存代码
- 【解决方案 七】---Git Merge时“交换文件.MERGE_MSG.swp已经存在”的问题
- python笔记(八)
- 【多目标追踪算法】Deepsort追踪实战
- 波斯顿翻跟头机器人_颤抖吧!波士顿动力机器人学会360度翻跟头,酷炫炸天……...
- Removing the Bias of Integral Pose Regression 阅读笔记
- C++入门:命名空间、缺省参数、函数重载、引用、内联函数、auto、范围for
- 给U盘/移动硬盘加密,防止借给别人的时候被查看
- 控制台界面控制(一)
- 动态规划练习题(3)开餐馆