一個同步工具,使得一個或多個線程等待一組線程執行完成後再執行。dom
使用場景:等待一些前置任務執行完成後,再執行特定的功能。好比,系統啓動時,各類配置生效後,才能運行提供服務。ide
public class CountDownLatchTest { public static void main(String[] args) { final CountDownLatch latch = new CountDownLatch(5); for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(new Random().nextInt(10)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " end, " + System.currentTimeMillis()); latch.countDown(); } }).start(); } try { System.out.println("main latch.await() " + System.currentTimeMillis()); latch.await(); System.out.println("main latch.await() end " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } }
特別注意:CountDownLatch初始化時,數量必定要等於等待的線程的數量。工具
CyclicBarrier(可循環同步屏障),控制一組線程相互等待,直到全部線程都到達屏障點。全部線程都到達屏障點後,同時開始執行剩餘的任務。ui
可循環,意味着當全部線程都到達屏障後,屏障能夠被再次重複利用。線程
多個任務同時到達某個臨界狀況時,才能同時執行剩餘任務,不然相互等待。code
public class CyclicBarrierTest { public static void main(String[] args) { int num = 3; final CyclicBarrier barrier = new CyclicBarrier(num); for (int i = 0; i < num; i++) { new Thread(new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(new Random().nextInt(5)); System.out.println(Thread.currentThread().getName() + "執行結束,開始等待其它線程, " + System.currentTimeMillis()); barrier.await(); System.out.println(Thread.currentThread().getName() + "全部線程等待都執行完成,開始執行剩下任務, " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }).start(); } // 屏障能夠在上一次使用完成後被再次使用 for (int i = 0; i < num; i++) { new Thread(new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(new Random().nextInt(5)); System.out.println(Thread.currentThread().getName() + "執行結束,開始等待其它線程, " + System.currentTimeMillis()); barrier.await(); System.out.println(Thread.currentThread().getName() + "全部線程等待都執行完成,開始執行剩下任務, " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }).start(); } System.out.println("main end at " + System.currentTimeMillis()); } }
Semaphore(信號量),一個計數信號量。概念上,一個信號量維持了一個許可集合。對象
實際上,並無真正的許可對象,只是計數。資源
限制資源同時被訪問的線程數量get
public class SemaphoreTest { public static void main(String[] args) { final Semaphore semaphore = new Semaphore(3); for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + "嘗試獲取許可, " + System.currentTimeMillis()); semaphore.acquire(); System.out.println(Thread.currentThread().getName() + "獲取許可, " + System.currentTimeMillis()); TimeUnit.SECONDS.sleep(new Random().nextInt(5)); System.out.println(Thread.currentThread().getName() + "執行結束, " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } } }).start(); } System.out.println("main end! " + System.currentTimeMillis()); } }
特別注意:得到許可並執行完邏輯後,必定要釋放,不然許可不會被歸還。(有借有還,再借不難)同步