Java併發包的門栓
阿新 • • 發佈:2018-11-29
package ThreadLearn; /** * 曾經的面試題:(淘寶?) * 實現一個容器,提供兩個方法,add,size * 寫兩個執行緒,執行緒1新增10個元素到容器中,執行緒2實現監控元素的個數,當個數到5個時,執行緒2給出提示並結束 * * 給lists新增volatile之後,t2能夠接到通知,但是,t2執行緒的死迴圈很浪費cpu,如果不用死迴圈,該怎麼做呢? * * 這裡使用wait和notify做到,wait會釋放鎖,而notify不會釋放鎖 * 需要注意的是,運用這種方法,必須要保證t2先執行,也就是首先讓t2監聽才可以 * * 閱讀下面的程式,並分析輸出結果 * 可以讀到輸出結果並不是size=5時t2退出,而是t1結束時t2才接收到通知而退出 * 想想這是為什麼? * * notify之後,t1必須釋放鎖,t2退出後,也必須notify,通知t1繼續執行 * 整個通訊過程比較繁瑣 * * 使用Latch(門閂)替代wait notify來進行通知 * 好處是通訊方式簡單,同時也可以指定等待時間 * 使用await和countdown方法替代wait和notify * CountDownLatch不涉及鎖定,當count的值為零時當前執行緒繼續執行 * 當不涉及同步,只是涉及執行緒通訊的時候,用synchronized + wait/notify就顯得太重了 * 這時應該考慮countdownlatch/cyclicbarrier/semaphore * */ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public class T019_05 { // 新增volatile,使t2能夠得到通知 volatile List lists = new ArrayList(); public void add(Object o) { lists.add(o); } public int size() { return lists.size(); } public static void main(String[] args) { T019_05 c = new T019_05(); CountDownLatch latch = new CountDownLatch(1); new Thread(() -> { System.out.println("t2啟動"); if (c.size() != 5) { try { latch.await(); //也可以指定等待時間 //latch.await(5000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t2 結束"); }, "t2").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e1) { e1.printStackTrace(); } new Thread(() -> { System.out.println("t1啟動"); for (int i = 0; i < 10; i++) { c.add(new Object()); System.out.println("add " + i); if (c.size() == 5) { // 開啟門閂,讓t2得以執行 latch.countDown(); } try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t1").start(); } }