juc.CountDownLatch 閉鎖
一個線程在等待一組線程后再恢復執行
await()等待其他線程執行完畢
被等待線程執行完畢后計數器-1
如何知道其他線程執行完了?
計數器,若一組線程為,CountDown為5,減到0代表等待線程被全部執行完畢
一次性工具:當Countdown的值減到0的時候再也無法恢復
juc內部的代碼都是lock體系來實現的
import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; // 運動員線程 class CDLTask implements Runnable { private CountDownLatch countDownLatch; public CDLTask(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } @Override public void run() { System.out.println(Thread.currentThread().getName()+"開始跑步"); try { TimeUnit.SECONDS.sleep(1); System.out.println(Thread.currentThread().getName()+"到達終點"); countDownLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } } public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(4); CDLTask cdlTask = new CDLTask(countDownLatch); System.out.println("比賽開始..."); new Thread(cdlTask,"運動員A").start(); new Thread(cdlTask,"運動員B").start(); new Thread(cdlTask,"運動員C").start(); new Thread(cdlTask,"運動員D").start(); // 等待所有線程都到達終點后再輸出此語句 countDownLatch.await(); System.out.println("比賽結束..."); } }
juc.CyclicBarrier 循環柵欄
一組線程同時到達臨界點后再恢復執行(先到達臨界點的線程會阻塞,直到所有線程都到達臨界點)
public CyclicBarrier(int parties, Runnable barrierAction)
當多個線程同時到達臨界點時,
隨機挑選一個線程執行barrierAction后再同時恢復執行
計數器的值可以恢復
await
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; class CBTask implements Runnable { private CyclicBarrier cyclicBarrier; public CBTask(CyclicBarrier cyclicBarrier) { this.cyclicBarrier = cyclicBarrier; } @Override public void run() { System.out.println(Thread.currentThread().getName()+ "正在寫入數據..."); try { TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()+ "寫入數據完畢,等待其他線程寫入完畢..."); cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println("所有線程均已寫入完畢,繼續恢復執行..."); } } class CyclicBarrierDemo { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(4 ,() -> { System.out.println("當前線程為:"+Thread.currentThread().getName()); }); CBTask cbTask = new CBTask(cyclicBarrier); for (int i = 0; i < 4; i++) { new Thread(cbTask,"寫線程"+(i+1)).start(); } } }
juc.Exchanger 線程交換器
用於兩個線程直線的數據交換,當Exchanger只有一個線程時,該線程會阻塞直到有別的線程
調用exchange進入緩沖區,當前線程與新線程交換數據后同時恢復執行。
import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit; class ExchangerDemo { public static void main(String[] args) { Exchanger<String> exchanger = new Exchanger<>(); Thread girlThread = new Thread(() -> { try { String girl = exchanger.exchange("我喜歡你....."); System.out.println("女生說:"+girl); } catch (InterruptedException e) { e.printStackTrace(); } }); girlThread.start(); Thread boyThread = new Thread(() -> { System.out.println("女神緩緩步入眼簾..."); try { TimeUnit.SECONDS.sleep(1); String boy = exchanger.exchange("我喜歡你!"); System.out.println("男生說:"+boy); } catch (InterruptedException e) { e.printStackTrace(); } }); boyThread.start(); } }

juc.Semaphore 信號量
acquire() : 嘗試占用一個信號量,失敗的線程會阻塞直到有新的信號量
release() : 釋放一個信號量
acquire(int n) : 嘗試占用n個信號量,失敗的線程會阻塞直到有新的信號量
release(int n) : 釋放n個信號量
import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; class SemaphoreTask implements Runnable { private Semaphore semaphore; public SemaphoreTask(Semaphore semaphore) { this.semaphore = semaphore; } @Override public void run() { try { semaphore.acquire(2); System.out.println(Thread.currentThread() .getName()+"占用2台設備生產"); TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread() .getName()+"生產完畢,釋放設備"); semaphore.release(2); } catch (InterruptedException e) { e.printStackTrace(); } } } class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(5); SemaphoreTask task = new SemaphoreTask(semaphore); for (int i = 0; i < 8; i++) { new Thread(task,"工人"+(i+1)).start(); } } }
這里有一篇比較好的博客關於cyclicbarrier和countdownlatch的區別: