在java1.5中引入了一些很重要的併發工具類好比:CyclicBarrier、Semaphore、countDownLatch、concurrentHashMap和BlockingQueue。今天咱們就來重點聊一聊經常使用的CyclicBarrier、Semaphore、countDownLatch這三個併發工具類。java
概念:countDownLatch這個類使一個線程等待其餘線程各自執行完畢後再執行。是經過一個計數器來實現的,計數器的初始值是線程的數量。每當一個線程執行完畢後,計數器的值就-1,當計數器的值爲0時,表示全部線程都執行完畢,而後在閉鎖上等待的線程就能夠恢復工做了。併發
做用:讓一些線程阻塞直到另一些線程完成一些列操做以後才被喚醒,CountDownLatch主要有兩個方法,當一個或者多個線程調用await()方法時候,調用線程會阻塞。其餘線程調用countDown方法會將計數器減1(調用CountDown方法的線程不會阻塞)。當計數器的值變成0時候,因調用await方法被阻塞的線程會被喚醒,繼續執行。工具
//參數count爲計數值 public CountDownLatch(int count) { }; //調用await()方法的線程會被掛起,它會等待直到count值爲0才繼續執行 public void await() throws InterruptedException { }; //和await()相似,只不過等待必定的時間後count值還沒變爲0的話就會繼續執行 public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //將count值減1 public void countDown() { };
場景:放學後5個同窗分別走出教室,每一個同窗走出教室前都要關燈(一個線程表明一個同窗),只有當5名同窗都走完以後門衛纔會把門關掉。難點:因爲線程結束順序是不可預知的,而在這個場景中只有前5個學生線程執行結束後,門衛線程才能執行。ui
public class CountDownLatchDemo { public static void main(String[] args) { for (int i = 0; i < 5; i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName() + " 關燈走人"); },String.valueOf(i)).start(); } System.out.println("人走完,門衛最後鎖門"); } } 人走完,門衛最後鎖門 0 關燈走人 3 關燈走人 2 關燈走人 1 關燈走人 4 關燈走人
使用CountDownLatch完成操作系統
public class CountDownLatchDemo { public static void main(String[] args) { CountDownLatch count = new CountDownLatch(5); for (int i = 0; i < 5; i++) { new Thread(()->{ System.out.println(Thread.currentThread().getName() + " 關燈走人"); count.countDown(); },String.valueOf(i)).start(); } try { count.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("人走完,門衛最後鎖門"); } } 1 關燈走人 2 關燈走人 0 關燈走人 3 關燈走人 4 關燈走人 人走完,門衛最後鎖門
CyclicBarrier的字面意思是可循環(Cyclic)使用的屏障(Barrier)。它要作的事情是讓一組線程到達一個屏障(也能夠叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,全部被屏障攔截的線程纔會繼續幹活,線程進入屏障經過CyclicBarrier的await()方法。線程
public CyclicBarrier(int parties) public CyclicBarrier(int parties, Runnable barrierAction)
public int await() throws InterruptedException, BrokenBarrierException public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
舉例:集齊七顆龍珠才能召喚神龍code
public class CyclicBarrierDemo { public static void main(String[] args) { //第二個參數是一個Runnable接口實現類,只有被cyclicBarrier阻塞的線程達到7個的時候Runnable纔會執行,也就是說傳入的線程只有等規定數量線程被阻塞以後才能執行。 CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{ System.out.println("成功集齊7龍珠,召喚神龍"); }); for (int i = 0; i < 7; i++) { final int temp = i; new Thread(()->{ System.out.println("已經收集第"+(temp+1)+"顆龍珠"); try { cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println("龍珠"+temp); }).start(); } } } 已經收集第2顆龍珠 已經收集第1顆龍珠 已經收集第3顆龍珠 已經收集第4顆龍珠 已經收集第5顆龍珠 已經收集第6顆龍珠 已經收集第7顆龍珠 成功集齊7龍珠,召喚神龍 龍珠6 龍珠1 龍珠4 龍珠3 龍珠5 龍珠2 龍珠0
CountDownLatch和CyclicBarrier區別:接口
信號量主要用於兩個目的,一個是用於共享資源的互斥使用,另外一個是用於併發線程數量的控制資源
相似於操做系統課程裏邊線程同步裏邊的信號量機制。(這個信號量機制但是很強大的喲)get
舉例:多個線程搶佔多個資源,在傳統的synchronized或者lock中適合於多個線程搶佔一個共享資源類,若是要實現多個線程搶佔多個資源類就有點無能爲力。
public class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(3);//模擬三個車位 for (int i = 0; i < 6; i++) { new Thread(()->{ try { semaphore.acquire();//信號量-1 System.out.println(Thread.currentThread().getName()+" 搶到停車場車位"); //線程休眠 try{ TimeUnit.SECONDS.sleep(3); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 停車三秒後退出停車場"); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release();//信號量+1 } },String.valueOf(i)).start(); } } } 0 搶到停車場車位 1 搶到停車場車位 2 搶到停車場車位 0 停車三秒後退出停車場 3 搶到停車場車位 1 停車三秒後退出停車場 2 停車三秒後退出停車場 5 搶到停車場車位 4 搶到停車場車位 3 停車三秒後退出停車場 5 停車三秒後退出停車場 4 停車三秒後退出停車場