文章插图
对象锁:任何一个对象都可以被当做锁,所以称为对象锁,比如下方代码lock1和lock2就是两把对象锁,都有自己独立的锁池和等待池
- 调用 lock1.wait() 就是该线程进入到lock1对象锁的等待池中
- lock1.notify()就是唤醒lock1对象锁的等待池中的随机一个等待线程,lock1.notifyAll(); 就是唤醒该等待池中所有等待线程
- lock1的锁池和等待池与lock2是独立的,互不影响,并不会唤醒彼此等待池中的线程
// 锁1private Object lock1 = new Object();// 锁2private Object lock2 = new Object();public void cook() {// 使用lock1对象锁synchronized (lock1) {lock1.wait();}lock1.notify();}
调用wait、notify、notifyAll之后线程变化:- 如果线程调用了对象的wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁 。
- 当有线程调用了对象的notifyAll()方法【唤醒所有该对象等待池中的 wait 线程】或 notify()方法【只随机唤醒一个该对象等待池中的 wait 线程】,被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁 。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
- 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用wait()方法,它才会重新回到等待池中 。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁 。
KitChenRoom中有 cook 和 eat 两个方法都是有同步代码块,并且进入while之后就会调用lock对象锁的wait方法,所以多个调用过cook和eat方法的线程就会进入等待池处于阻塞状态,等待一个正在运行的线程来唤醒它们 。下面分别分析一下使用notify和notifyAll方法唤醒线程的不同之处:
- 使用notify:notify方法只能唤醒一个线程,其它等待的线程仍然处于wait状态,假设调用cook方法的线程执行完后,所有的线程都处于等待状态,此时又执行了notify方法,这时如果唤醒的仍然是一个调用cook方法的线程【比如爸爸线程 将 妈妈线程唤醒】,那么while循环等于true,则此唤醒的线程【妈妈线程】就会调用wait方法,也会处于等待状态,而且没有唤醒其他线程,那就芭比Q了,此时所有的线程都处于等待状态,就发生了死锁 。
- 使用notifyAll:可以唤醒所有正在等待该锁的线程,那么所有的线程都会处于运行前的准备状态(就是cook方法执行完后,唤醒了所有等待该锁的线程),那么此时,即使再次唤醒一个调用cook方法的线程,while循环等于true,唤醒的线程再次处于等待状态,那么还会有其它的线程可以获得锁,进入运行状态 。
- 通过调用notifyAll唤醒所有等待线程
- 调用 wait(long timeout) 重载方法,设置等待超时时长,在指定时间内还没被唤醒则自动醒来
public class KitChenRoom {private boolean hasFood = false;private Object lock = new Object();public void cook() {synchronized (lock) {while (hasFood) {try {// 超时等待 2 秒lock.wait(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(Thread.currentThread().getName() + "没吃的了,给娃做饭!");hasFood = true;lock.notify();}}public void eat() {synchronized (lock) {while (!hasFood) {try {// 超时等待 2 秒lock.wait(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(Thread.currentThread().getName() + "感谢老妈,恰饭,恰饭");hasFood = false;lock.notify();}}}
运行结果:运行三次发现,第一次程序陷入了两次等待2秒之后程序继续执行,这就是超时自动唤醒,避免了死锁
推荐阅读
- 一个水煮鸡蛋白的热量
- 重庆|3条私密视频外泄!景甜你糊涂呀,张柏芝阿娇的血泪教训你不懂吗
- 夏文汐|香港知名女星突然宣布复出,疑与富商丈夫离婚,多次被传和小鲜肉搞暧昧
- 景甜|3条私密视频外泄!景甜你糊涂呀,张柏芝阿娇的血泪教训你不懂吗
- 隐婚|大瓜!已婚男星与85后女闺蜜关系不纯,早先隐婚便于乱搞
- 隐婚|曝翻红男星婚后乱搞,与85花闺蜜乱玩,隐婚多年因方便约会
- 隐婚|大瓜!曝已婚翻红男星与85后女闺蜜关系不纯,早先隐婚便于乱搞
- |处于上升期的职场年轻人,到底该不该搞副业?
- 电影|何莉莉:你们笑我是风月片女王,我笑你们不懂70亿港币是有多重!
- 一个胡萝卜的热量