最近在研究wait和notify方法,發現有個地方要注意,但是網上又說得不是很明白的地方,就是經典的生產者和消費模式,使用wait和notify實現,判斷list是否為空的這個為什么要用while而不能使用if呢?其實是因為當線程wait之后,又被喚醒的時候,是從wait后面開始執行,而不是又從頭開始執行的,所以如果用if的話,被喚醒之后就不會在判斷if中的條件,而是繼續往下執行了,如果list只是添加了一個數據,而存在兩個消費者被喚醒的話,就會出現溢出的問題了,因為不會在判斷size是否==0就直接執行remove了。但是如果使用while的話,從wait下面繼續執行,還會返回執行while的條件判斷,size>0了才會執行remove操作,所以這個必須使用while,而不能使用if來作為判斷。
以下代碼是一個簡單的實踐,參考:
http://www.cnblogs.com/hapjin/p/5492645.html(做了適當的調整)
Add類,負責添加數據:
public class Add { private String lock; public Add(String lock) { super(); this.lock = lock; } public void add() { synchronized (lock) { ValueObject.list.add("anyString"); lock.notifyAll(); } } } public class ThreadAdd extends Thread { private Add p; public ThreadAdd(Add p) { super(); this.p = p; } @Override public void run() { p.add(); } }
Subtract類,負責刪除數據
public class Subtract { private String lock; public Subtract(String lock) { super(); this.lock = lock; } public boolean check() { System.out.println("check"); return true; } public void subtract() { try { synchronized (lock) { if(check() && ValueObject.list.size() == 0) {//將這里的if改成while即可保證不出現越界異常!!!! System.out.println("wait begin ThreadName=" + Thread.currentThread().getName()); lock.wait(); System.out.println("wait end ThreadName=" + Thread.currentThread().getName()); } ValueObject.list.remove(0); System.out.println("list size=" + ValueObject.list.size()); } } catch (InterruptedException e) { e.printStackTrace(); } } } public class ThreadSubtract extends Thread { private Subtract r; public ThreadSubtract(Subtract r) { super(); this.r = r; } @Override public void run() { r.subtract(); } }
封裝的List隊列:
public class ValueObject { public static List list = new ArrayList(); }
測試類:
public class Run { public static void main(String[] args) throws InterruptedException { String lock = new String(""); Add add = new Add(lock); Subtract subtract = new Subtract(lock); ThreadSubtract subtract1Thread = new ThreadSubtract(subtract); subtract1Thread.setName("subtract1Thread"); subtract1Thread.start(); ThreadSubtract subtract2Thread = new ThreadSubtract(subtract); subtract2Thread.setName("subtract2Thread"); subtract2Thread.start(); Thread.sleep(1000); ThreadAdd addThread = new ThreadAdd(add); addThread.setName("addThread"); addThread.start(); } }