java编程思想笔记-并发之线程协作(一)
来源:互联网 发布:电脑数据怎么恢复 编辑:程序博客网 时间:2024/06/09 18:22
1.wait和notifyAll简单使用
1.通过wait使当前线程挂起,并释放当前线程持有的锁,而sleep和yield方法则不会释放自己拥有的锁
2.通过notify()或者notifyAll使wait的时间到期
3.wait(),notifyAll(),notify()方法都是基类的一部分而不属于线程
4.wait(),notifyAll(),notify()在调用前必须获取对象锁,否则虽然程序能够通过编译,但是运行时候会得到IllegalMonitorStateException异常
汽车打蜡与抛光的例子:
汽车每打一次蜡必须抛光一次,而抛光不能发生在打蜡之前
package com.tij.thread.cooperate;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;class Car{ private boolean waxOn=false; public synchronized void waxed(){ waxOn=true; notifyAll(); } public synchronized void buffed(){ waxOn=false; notifyAll(); } //必须让线程获取锁线程才能wait //打蜡之前通过waxOn不停的检查是否已经经过抛光 public synchronized void waitForWaxing() throws InterruptedException { //一定要使用循环检查,避免其它线程再次改变了条件而当前线程不知道 while (!waxOn) { wait(); } } //必须让线程获取锁线程才能wait //抛光之前通过waxOn不停的检查是否已经经过打蜡 public synchronized void waitForBuffing()throws InterruptedException{ //一定要使用循环检查,避免其它线程再次改变了条件而当前线程不知道 while (waxOn) { wait(); } }}class WaxOn implements Runnable{ private Car car; public WaxOn(Car car){ this.car=car; } @Override public void run() { try { while (!Thread.interrupted()) { System.out.println(" Wax On "); TimeUnit.MILLISECONDS.sleep(200); car.waxed(); car.waitForBuffing(); } } catch (InterruptedException e) { System.out.println("WaxOn Exiting via interrupt "); } System.out.println(" Ending Wax On task "); }}class WaxOff implements Runnable{ private Car car; public WaxOff(Car car){ this.car=car; } @Override public void run() { try { while (!Thread.interrupted()) { car.waitForWaxing(); System.out.println(" Wax Off ! "); TimeUnit.MILLISECONDS.sleep(200); car.buffed(); } } catch (Exception e) { System.out.println("WaxOff 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 exec=Executors.newCachedThreadPool(); exec.execute(new WaxOff(car)); exec.execute(new WaxOn(car)); TimeUnit.SECONDS.sleep(5); exec.shutdownNow(); }}
一开始没有按照Thinking In Java里面的代码,我对WaxOn类进行了轻微的改动,将try,catch放到了循环的外面我认为这样的改动与Thinking In Java里面的代码没什么区别,代码如下
class WaxOn implements Runnable{ private Car car; public WaxOn(Car car){ this.car=car; } @Override public void run() { while (!Thread.interrupted()) { try { System.out.println(" Wax On "); TimeUnit.MILLISECONDS.sleep(200); car.waxed(); car.waitForBuffing(); } catch (InterruptedException e) { System.out.println("WaxOn Exiting via interrupt "); } } System.out.println(" Ending Wax On task "); }}
实际上这样的改变有潜在的问题,这会导致WaxOn任务始终无法退出循环,我们将WaxOn的睡眠时间调到2000ms来验证这一猜想,这个时候main线程发出shutdownNow()命令关闭线程池内所有的线程,但是WaxOn正在睡眠所以抛出异常,因为内部try-catch捕获了该异常,并在捕获中自动修改了interrupt标志为false,所以导致WaxOn始终进行循环
上面的例子使用的是线程机制进行协作,也可以不依赖于线程机制进行协作,如下面这个例子利用flag标记进行通信:
public class MessageTest { private static volatile boolean flag; private static int spins; public static void main(String[] args) throws InterruptedException { Runnable r1 = new Runnable() { @Override public void run() { while (true) { try { TimeUnit.MILLISECONDS.sleep(10); } catch (Exception e) { return; } flag = true; //System.out.println("set flag ---------------->"+flag); } } }; Runnable r2 = new Runnable() { @Override public void run() { while (true) { while (!flag && !Thread.currentThread().isInterrupted()) { spins++; } System.out.println("Spun " + spins + " times"); spins = 0; flag = false; if (Thread.interrupted()) { return; } } } }; ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(r1); exec.execute(r2); TimeUnit.SECONDS.sleep(10); exec.shutdownNow(); }}
2.notify()/wait()错失信号造成的死锁
T1synchronized(shareMonitor){ <setup condition for T2> sharedMonitor.notify();}T2while(someCondition){ synchronized(shareMonitor){ sharedMonitor.wait(); }}T2首先运行经过计算得出someCondition满足循环条件,线程调度器回到T1,T1通过<setup condition for T2>设置T2 someCondition为false,但是太晚T2已经进入了循环,同时T2继续运行notify(),并释放锁,T2得到锁并进入等待,但是notify已经错失,便造成了死锁,通过以下方法解决问题synchronized(shareMonitor){ //务必通过while来判断条件,避免错失条件改变 while(someCondition){ sharedMonitor.wait(); }}自此我们得到的启示是 1.调用notify的时候要仔细思考是否能通知到目标线程 2.wait前用while循环进行条件判断是否进行等待
阅读全文
0 0
- java编程思想笔记-并发之线程协作(一)
- java编程思想笔记-并发之线程协作(二)
- java编程思想笔记-并发之线程协作(三)
- java编程思想笔记-并发之线程协作(四)
- Java编程思想 之 线程协作
- java编程思想笔记-并发之并发锁(一)
- java编程思想笔记-并发之线程加入
- Java并发编程实战笔记(5)- 线程协作
- java编程思想笔记-并发之死锁
- java编程思想笔记-并发之CountDownLatch
- java编程思想笔记-并发之CyclicBarrier
- Java并发之线程之间协作
- Java并发之线程间的协作
- (38)21.3.8 线程本地存储---Java编程思想之并发笔记
- java编程思想笔记-并发之后台线程
- Java并发编程之线程(一)
- java编程思想-并发之线程异常处理器
- 并发(java编程思想)笔记
- dom事件
- solr 检索、分页、提取摘要和高亮
- Servlet安全性(1)----验证和授权
- disable-output-escaping
- Java实现随机无重复数字功能
- java编程思想笔记-并发之线程协作(一)
- JavaWeb学习总结(一)——JavaWeb开发入门
- UI设计中图形设计详解
- 【Leetcode】257 Binary Tree Paths 二叉树的路径
- 使用JDOM解析XML文件(JDOM解析)
- 关于Eclipse ProjectExplorer下文件的排序问题
- 微信网页开发——随手笔记
- Java加密解密等操作的工具类
- [总结]Java真是博大精深(一)