等待&通知机制
2018-02-06 15:03
239 查看
等待/通知机制
等待通知机制什么是等待通知机制
如何实现等待通知机制
wait 方法
notifynotifyAll 方法
线程状态切换
Runnable 状态 Running 状态
Running 状态 - Blocked 状态
Blocked 状态 - Runnable 状态
Dead 状态
waitnotify模式的注意事项
经典案例生产者消费者模式实现
实战等待通知之交叉备份
什么是等待/通知机制?
举例说明,厨师和服务员之间的交互:1. 厨师做完一道菜的时间不确定,所以厨师将菜品放到”菜品传递台”上的时间也不确定;
2. 服务员取到菜的时间取决于厨师,所以服务员就处于等待状态;
3. 服务员如何取到菜呢?又得取决于厨师,厨师将菜放在”菜品传递台”上,其实就相当于一种通知,这时服务员才可以拿到菜并交给就餐者。
如何实现等待/通知机制?
一句话总结:wait 使线程停止运行,而 notify 使停止的线程继续运行。wait() 方法
是 Object 类的方法,作用:使当前执行代码的线程进行等待,直到接到通知或被中断为止。执行之后,当前线程释放锁。
只能在同步方法或同步块中调用 wait()方法。原因:JDK 强制的,方法调用之前必须先获得该对象的对象级别锁,如果调用时没有持有适当的锁,则抛出 IllegalMonitorStateException 异常。
notify()/notifyAll() 方法
Object 类的方法,用来通知那些可能等待该对象的对象锁的其他线程。在执行 notify() 方法后,当前线程不能马上释放该对象锁,wait 状态的线程也不能马上获取该对象锁,需要等到执行 notify() 方法的线程执行完(退出 synchronized 代码块后)。
只能在同步方法或同步块中调用。原因如上。
线程状态切换
Runnable 状态 & Running 状态
Runnable:就绪状态,随时可能被 CPU 调度执行Running:运行状态,线程获取 CPU 权限进行执行
创建一个新的线程对象后,调用 start() 方法,系统为此线程分配 CPU 资源,线程进入 Runnable 状态
如果线程抢占到 CPU 资源,此线程进入 Running 状态
Running 状态 -> Blocked 状态
blocked:阻塞状态,线程放弃了 CPU 使用权,暂时停止运行,直到线程进入就绪状态。分为三种:1. 等待阻塞:调用 wait()方法,让线程等到某工作的完成
2. 同步阻塞:synchronized 获取对象锁失败(可能锁被占用)
3. 其他阻塞:调用 sleep() | join() | 发出 IO 请求时,线程进入阻塞。
线程调用 sleep() 方法,主动放弃占用的处理器资源
线程调用了阻塞式 IO 方法,在该方法返回前,该线程被阻塞
线程试图获得一个同步监视器,但该监视器正被其他线程所持有
线程调用 wait() 方法,等待某个通知
程序调用了 suspend 方法将该线程挂起。(此方法容易死锁,避免使用)
Blocked 状态 -> Runnable 状态
调用 sleep() 方法后,sleep()超时线程调用的阻塞 IO 已经返回,阻塞方法执行完毕
线程成功获得了试图同步的监视器
线程正在等到通知,其他线程发出了通知(notify() | notifyAll)
处于挂起状态的线程调用了 resume() 恢复方法
Dead 状态
线程执行完了或者异常退出了 run() 方法,结束生命周期。每个锁对象都有两个队列:
- 就绪队列:存储将要获得锁的线程,一个线程被唤醒后,进入就绪队列,等到 CPU 调度
- 阻塞队列:存储被阻塞的线程,一个线程被 wait() 后,进入阻塞队列,等待下一次被唤醒
wait/notify模式的注意事项
wait 释放锁,notify 不释放锁当线程处于 wait 状态时,使用 interrupt() 方法会出现 InterruptedException 异常
wait(long) 方法的作用:等待某一个时间内是否有线程对锁进行唤醒,如果超过时间则自动唤醒。
如果通知过早,则会打乱程序正常的运行逻辑。(wait 状态的线程不会被通知)
wait 等待的条件发生变化,也容易造成程序逻辑的混乱
经典案例:生产者/消费者模式实现
实战:等待/通知之交叉备份
创建 20 个线程,其中 10 个线程是将数据备份到 A 数据中,另外 10 个线程是将数据备份到 B 数据库中,并且备份 A 数据库和 B 数据库是交叉进行的。public class DBTools { // 确保备份 "★★★★★" 首先执行,然后与 "☆☆☆☆☆" 交替进行备份 volatile private boolean prevIsA = false; synchronized public void backupA() { try { while (prevIsA) { wait(); } for (int i = 0; i < 5; i++) { System.out.println("★★★★★"); } prevIsA = true; notifyAll(); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void backupB() { try { while (!prevIsA) { wait(); } for (int i = 0; i < 5; i++) { System.out.println("☆☆☆☆☆"); } c539 prevIsA = false; notifyAll(); } catch (InterruptedException e) { e.printStackTrace(); } } }
public class BackupA extends Thread { private DBTools dbTools; public BackupA(DBTools dbTools) { super(); this.dbTools = dbTools; } @Override public void run() { dbTools.backupA(); } }
public class BackupB extends Thread { private DBTools dbTools; public BackupB(DBTools dbTools) { super(); this.dbTools = dbTools; } @Override public void run() { dbTools.backupB(); } }
public class Run { public static void main(String[] args) { DBTools dbTools = new DBTools(); for (int i = 0; i < 20; i++) { BackupB output = new BackupB(dbTools); output.start(); BackupA input = new BackupA(dbTools); input.start(); } } }
相关文章推荐
- Java多线程之线程的等待&通知机制
- Java Concurrency - wait & notify, 等待通知机制
- java多线程中等待/通知机制
- 多线程__【线程间通信】【等待唤醒机制】【多生产多消费】【Lock&Condition接口】
- Java的等待通知机制
- java线程之间的通信(等待/通知机制)
- 多线程 等待/通知机制的实现
- java多线程系列(三)---等待通知机制
- 再谈AbstractQueuedSynchronizer2:共享模式与基于Condition的等待/通知机制实现
- 【转】BaseAdapter&DataSetObserver通知机制
- Java等待/通知机制:生产者-消费者问题
- 《多线程编程》学习之七:等待/通知机制(一)
- 《Java并发编程的艺术》读书笔记:等待/通知机制
- 等待/通知机制
- 二 Java利用等待/通知机制实现一个线程池
- 等待通知机制 wait,notify,notifyAll
- Java 并发编程-再谈 AbstractQueuedSynchronizer 2:共享模式与基于 Condition 的等待 / 通知机制实现
- java多线程之线程间通信:等待/通知机制
- 【多线程】线程通信之等待/通知机制
- 线程通信(1) - wait与notify,多线程中的等待与通知机制