現在兩個線程,可以操作初始值為零的一個變量,實現一個線程對該變量加1,一個線程對該變量減1,實現交替,來10輪,變量初始值為零。
package com.yangyuanyuan.juc1205; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Aircondition { private int number = 0; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void increment()throws Exception { lock.lock(); try { //1 判斷 while (number != 0) { condition.await();//this.wait(); } //2 干活 number++; System.out.println(Thread.currentThread().getName()+"\t"+number); //3 通知 condition.signalAll();//this.notifyAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void decrement()throws Exception { lock.lock(); try { //1 判斷 while (number == 0) { condition.await();//this.wait(); } //2 干活 number--; System.out.println(Thread.currentThread().getName()+"\t"+number); //3 通知 condition.signalAll();//this.notifyAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } /*public synchronized void increment()throws Exception { //1 判斷 while (number != 0) { //AAA CCC this.wait(); } //2 干活 number++; System.out.println(Thread.currentThread().getName()+"\t"+number); //3 通知 this.notifyAll(); } public synchronized void decrement()throws Exception { //1 判斷 while(number == 0) { this.wait(); } //2 干活 number--; System.out.println(Thread.currentThread().getName()+"\t"+number); //3 通知 this.notifyAll(); }*/ } /** 1 高聚低合前提下,線程操作資源類 2 判斷/干活/通知 3 防止虛假喚醒 不能使用if判斷,會出現2 知識小總結 = 多線程編程套路+while判斷+新版寫法 */ public class ProdConsumerDemo04 { public static void main(String[] args)throws Exception { Aircondition aircondition = new Aircondition(); new Thread(() -> { for (int i = 1; i <=10; i++) { try { Thread.sleep(200); aircondition.increment(); } catch (Exception e) { e.printStackTrace(); } } },"A").start(); new Thread(() -> { for (int i = 1; i <=10; i++) { try { Thread.sleep(300); aircondition.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"B").start(); new Thread(() -> { for (int i = 1; i <=10; i++) { try { Thread.sleep(400); aircondition.increment(); } catch (Exception e) { e.printStackTrace(); } } },"C").start(); new Thread(() -> { for (int i = 1; i <=10; i++) { try { Thread.sleep(500); aircondition.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"D").start(); } }
使用if判斷存在虛假喚醒情況,變量可能會變成2

如圖所示,如果只有兩個線程,一個線程加,一個線程減,不會存在虛假喚醒情況(選無可選)。
當變成四個線程時,兩個線程加,兩個線程減,使用if就會存在虛假喚醒情況。如變量初始為0(0!=0為false),執行完+’變量變成1,此時+線程進來發現值為1等待(this.wait()處等待,未出if判斷),然后+‘線程又進來發現值為1它也等待(this.wait()處等待,未出if判斷),此時-線程進來(1==0為false)發現變量值為1將變量做減法變成0。由於此時+和+‘仍在等待,cpu為了降低消耗量和負擔,會先滿足等待時間長的線程(線程優先級會高)
由於使用的是if,不會再拉回來重新判斷一次(兩個線程this.wait()處等待),+和+’線程都會做加法,變量值就變成了2。
