儿时的游戏:(等待 与 唤醒)
有一群小朋友一起玩一个游戏,这个游戏可能大家都玩过,大家一起划拳,划拳输得最惨的那个小朋友去抓人(这个小朋友取名为 CPU),被抓的很多人取名为线程,有很多线程,如果其中一个小朋友(例如:Thread-3) 被木头了(wait();) 就站着不准动了(冻结状态),Thread-3小朋友站着不动(冻结状态) CPU小朋友就不会去抓Thread-3小朋友,因为Thread-3小朋友(释放CPU执行资格) 需要其他小朋友(例如:Thread-5) 去啪一下Thread-3小朋友(notify();), 此时Thread-3小朋友就可以跑了(被唤醒) 此时Thread-3小朋友具备被抓的资格(具备CPU执行资格),能否被抓得到 要看CPU小朋友的随机抓人法(CPU切换线程的随机性)
等待唤醒机制:
wait(); 等待/冻结 :可以将线程冻结,释放CPU执行资格,释放CPU执行权,并把此线程临时存储到线程池
notify(); 唤醒线程池里面 任意一个线程,没有顺序;
notifyAll(); 唤醒线程池里面,全部的线程;
使用等待唤醒注意事项:
1.使用来wait();冻结,就必须要被其他方notify();,否则一直wait()冻结,所以等待与唤醒是配合一起使用的;
2.wait(); notify(); notifyAll(); 等方法必须被synchronized(锁) {包裹起来},意思就是:wait(); notify(); notifyAll(); 必须要有同步锁🔒,否则毫无意义;
3.wait(); notify(); notifyAll(); 等方法必须持有同一把锁🔒,因为:lockA.wait(); 只能使用 lockA.notify(); / lockA.notifyAll(); , 它们是使用同一把锁🔒的;
等待:🔒锁.wait();
唤醒:🔒锁.notify();
唤醒:🔒锁.notifyAll();
代码分析 1:
❌❌❌❌❌ 错误的示范,public synchronized (锁🔒== this) void testMethod1(){} ,然后却是OBJ_LOCK.notify(); this锁🔒和 OBJ_LOCK🔒不一致,是错误的,没有共用一把锁
private final Object OBJ_LOCK = new Object(); /** * public synchronized void testMethod1(){} * synchronized的锁🔒是this / b = new TestWaitNotifyDemo(); b也是 * 所以可以:this.notify(); this.notifyAll(); this.wait(); */ public synchronized void testMethod1() { /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ OBJ_LOCK.notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 唤醒所有 */ OBJ_LOCK.notifyAll(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { OBJ_LOCK.wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } }
✅✅✅✅✅,正确的方式:public synchronized(🔒锁==this) void testMethod1, this.notify(); this.notifyAll(); this.wait();
/** * public synchronized void testMethod1(){} * synchronized的锁🔒是this / b = new TestWaitNotifyDemo(); b也是 * 所以可以:this.notify(); this.notifyAll(); this.wait(); */ public synchronized void testMethod1() { /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ this.notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 唤醒所有 */ this.notifyAll(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { this.wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } }
代码分析 1 伪代码:
public synchronized(🔒锁是this) void testMethod1() { 锁🔒this.notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 锁🔒this.notifyAll(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 锁🔒this.wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 }
代码分析 2:
错误的示范❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌❌ synchronized (锁🔒== OBJ_LOCK) ,然后却是this.notify(); this锁🔒和 OBJ_LOCK🔒不一致,是错误的
private final Object OBJ_LOCK = new Object(); public void testMethod2() throws InterruptedException { /** * synchronized (OBJ_LOCK) {} * synchronized的锁🔒是 OBJ_LOCK * 所以可以:OBJ_LOCK.notify(); OBJ_LOCK.notifyAll(); OBJ_LOCK.wait(); */ synchronized (OBJ_LOCK) { /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ this.notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 唤醒所有 */ this.notifyAll(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ this.wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 } }
正确的示范✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅synchronized (锁🔒== OBJ_LOCK) ,然后是OBJ_LOCK.notify(); 使用了同一把OBJ_LOCK锁🔒,是正确的✅
private final Object OBJ_LOCK = new Object(); public void testMethod2() throws InterruptedException { /** * synchronized (OBJ_LOCK) {} * synchronized的锁🔒是 OBJ_LOCK * 所以可以:OBJ_LOCK.notify(); OBJ_LOCK.notifyAll(); OBJ_LOCK.wait(); */ synchronized (OBJ_LOCK) { /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ OBJ_LOCK.notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 唤醒所有 */ OBJ_LOCK.notifyAll(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ OBJ_LOCK.wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 } }
代码分析 2 伪代码:
private final Object OBJ_LOCK = new Object(); public void testMethod2() throws InterruptedException { synchronized (OBJ_LOCK🔒锁) { /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ OBJ_LOCK🔒锁.notify(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 唤醒所有 */ OBJ_LOCK🔒锁.notifyAll(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ OBJ_LOCK🔒锁.wait(); // 注意:⚠️ wait(); notify(); 这些必须要有同步锁包裹着 } }
                    
                
                
            
        
浙公网安备 33010602011771号