講解等待喚醒機制以前,有必要搞清一個概念——dom
線程之間的通訊:ide
多個線程在處理同一個資源,可是處理的動做(線程的任務)卻不相同。經過必定的手段使各個線程能有效的利用資源。而這種手段即—— 等待喚醒機制。this
等待喚醒機制所涉及到的方法:spa
wait() :等待,將正在執行的線程釋放其執行資格 和 執行權,並存儲到線程池中。線程
notify():喚醒,喚醒線程池中被wait()的線程,一次喚醒一個,並且是任意的。orm
notifyAll(): 喚醒所有:能夠將線程池中的全部wait() 線程都喚醒。資源
public class NumberHolder { private int number; public synchronized void increase() { if (0 != number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能執行到這裏說明已經被喚醒 // 而且number爲0 number++; System.out.println(number); // 通知在等待的線程 notify(); } public synchronized void decrease() { if (0 == number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能執行到這裏說明已經被喚醒 // 而且number不爲0 number--; System.out.println(number); notify(); } }public class IncreaseThread extends Thread { private NumberHolder numberHolder; public IncreaseThread(NumberHolder numberHolder) { this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 進行必定的延時 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 進行增長操做 numberHolder.increase(); } } }public class DecreaseThread extends Thread { private NumberHolder numberHolder; public DecreaseThread(NumberHolder numberHolder) { this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 進行必定的延時 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 進行減小操做 numberHolder.decrease(); } } }public class NumberTest { public static void main(String[] args) { NumberHolder numberHolder = new NumberHolder(); Thread t1 = new IncreaseThread(numberHolder); Thread t2 = new DecreaseThread(numberHolder); t1.start(); t2.start(); } }
由於就是兩個線程因此就是能夠互相切換,即必須是互相切換,可是若是是四個線程呢?會怎麼樣呢?it
那麼再來兩個線程;io
即把其中的NumberTest類改成以下:class
public class NumberTest { public static void main(String[] args) { NumberHolder numberHolder = new NumberHolder(); Thread t1 = new IncreaseThread(numberHolder); Thread t2 = new DecreaseThread(numberHolder); Thread t3 = new IncreaseThread(numberHolder); Thread t4 = new DecreaseThread(numberHolder); t1.start(); t2.start(); t3.start(); t4.start(); } }
爲何兩個線程的時候執行結果正確而四個線程的時候就不對了呢?
由於線程在wait()的時候,接收到其餘線程的通知,即往下執行,再也不進行判斷。兩個線程的狀況下,喚醒的確定是另外一個線程;可是在多個線程的狀況下,執行結果就會混亂無序。
好比,一個可能的狀況是,一個增長線程執行的時候,其餘三個線程都在wait,這時候第一個線程調用了notify()方法,其餘線程都將被喚醒,而後執行各自的增長或減小方法。
解決的方法就是:在被喚醒以後仍然進行條件判斷,去檢查要改的數字是否知足條件,若是不知足條件就繼續睡眠。把兩個方法中的if改成while便可。
public class NumberHolder { private int number; public synchronized void increase() { while (0 != number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能執行到這裏說明已經被喚醒 // 而且number爲0 number++; System.out.println(number); // 通知在等待的線程 notify(); } public synchronized void decrease() { while (0 == number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能執行到這裏說明已經被喚醒 // 而且number不爲0 number--; System.out.println(number); notify(); } }
這樣就能夠解決了線程的混亂的問題。