- CountDownLatch:一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。
- CyclicBarrier:一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點
- Semaphore:一個計數信號量
- Exchanger:方便了兩個共同操作線程之間的雙向交換
CountDownLatch
CountDownLatch有一個正數計數器,countDown方法對計數器做減操作,await方法等待計數器達到0。所有await的線程都會阻塞直到計數器爲0或者等待線程中斷或者超時。
- public CountDownLatch(int count) 初始化計數器個數
- public void await() 計數器不爲0時,線程一直阻塞
- public boolean await(long timeout, TimeUnit unit) 計數器不爲0時或 指定的等待時間沒有過去,線程一直阻塞
- public void countDown() 減少計數器的計數,如果計數達到零,則釋放所有等待的線程。
- public long getCount() 返回當前計數
@Slf4j public class CountDownLatchDemo { private static final Integer THREAD_COUNT_NUM = 50; private static ExecutorService singleThreadPool; static { ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("jack").build(); singleThreadPool = new ThreadPoolExecutor( 10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); } /** * CountDownLatch是一個同步的輔助類,允許一個或多個線程,等待其他一組線程完成操作,再繼續執行。 */ public static void main(String[] args) { log.info("準備50個線程"); LocalDateTime start = LocalDateTime.now(); CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT_NUM); for (int i = 0; i < THREAD_COUNT_NUM; i++) { Integer index = i; singleThreadPool.execute(() -> { //設置線程名 String threadName = "線程" + index.toString(); log.info("thread {} is start...",threadName); try { //do something log.info("{} do something ...",threadName); } catch (Exception e){ log.error(e.getMessage()); }finally { countDownLatch.countDown(); } }); } //計數器必須大於等於0,只是等於0的時候,計數器就是0,調用await方法時不會阻塞當前線程。 try { countDownLatch.await(); } catch (InterruptedException e) { log.error(e.getMessage()); } //後續操作 LocalDateTime end = LocalDateTime.now(); Duration duration = Duration.between(start, end); log.info("執行時間爲{}", duration.toMillis()); } }
CyclicBarrier
一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因爲該 barrier 在釋放等待線程後可以重用,所以稱它爲循環 的 barrier。CyclicBarrier 支持一個可選的 Runnable 命令,在一組線程中的最後一個線程到達之後(但在釋放所有線程之前),該命令只在每個屏障點運行一次。若在繼續所有參與線程之前更新共享狀態,此屏障操作 很有用。
- public CyclicBarrier(int parties, Runnable barrierAction) 當await的數量到達了設定的數量後,首先執行該Runnable對象。
- public CyclicBarrier(int parties) 設置parties、count及barrierCommand屬性。
- public int getParties() 返回跳過此障礙所需的參與方數量。
- public int await() 線程阻塞
- public int await(long timeout, TimeUnit unit) 線程阻塞
- public boolean isBroken() 查詢此屏障是否處於損壞狀態
- public void reset() 重置屏障
- public int getNumberWaiting()
@Slf4j public class CyclicBarrierDemo { private static final Integer THREAD_COUNT_NUM = 50; private static ExecutorService singleThreadPool; static { ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("jack").build(); singleThreadPool = new ThreadPoolExecutor( 50, 50, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); } /** * CyclicBarrier是一個同步的輔助類,允許一組線程相互之間等待,達到一個共同點,再繼續執行。 */ public static void main(String[] args) { //循環屏障1 準備50給線程集結完畢 //當await的數量到達了設定的數量後,首先執行該Runnable對象。 CyclicBarrier cyclicBarrier = new CyclicBarrier(THREAD_COUNT_NUM, () -> { log.info("50個線程準備完畢"); //50個線程集結完畢後開始工作 CyclicBarrier cyclicBarrier1 = new CyclicBarrier(THREAD_COUNT_NUM, () -> log.info("50個線程工作完畢")); for (int i = 0; i < THREAD_COUNT_NUM; i++) { Integer index = i; singleThreadPool.execute(() -> { log.info("第 {} 個線程開始工作", index); try { //通知屏障,我已到達 cyclicBarrier1.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }); } }); for (int i = 0; i < THREAD_COUNT_NUM; i++) { Integer index = i; singleThreadPool.execute(() -> { log.info("第 {} 個線程已經準備完畢", index); try { //通知屏障,我已到達 cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }); } } }
Semaphore
Semaphore是一個計數器,在計數器不爲0的時候對線程就放行,一旦達到0,那麼所有請求資源的新線程都會被阻塞,包括增加請求到許可的線程,也就是說Semaphore不是可重入的。每一次請求一個許可都會導致計數器減少1,同樣每次釋放一個許可都會導致計數器增加1,一旦達到了0,新的許可請求線程將被掛起。
- public void acquire() 從此信號量獲取一個許可,在提供一個許可前一直將線程阻塞,否則線程被中斷。
- public void release() 釋放一個許可,將其返回給信號量。
- public int availablePermits() 返回此信號量中當前可用的許可數。
- public final boolean hasQueuedThreads() 查詢是否有線程正在等待獲取
@Slf4j public class SemaphoreDemo { private static final Integer THREAD_COUNT_NUM = 50; private static final Integer MAX_THREAD_COUNT_NUM = 10; private static ExecutorService singleThreadPool; static { ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("jack").build(); singleThreadPool = new ThreadPoolExecutor( 50, 50, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); } public static void main(String[] args) { Semaphore semaphore = new Semaphore(MAX_THREAD_COUNT_NUM); for (int i = 0; i < THREAD_COUNT_NUM; i++) { Integer index = i; //模擬線程執行時間 try { Thread.sleep(100); } catch (InterruptedException e) { log.error(e.getMessage()); } singleThreadPool.execute(() -> { try { //獲得許可證 semaphore.acquire(); Thread.sleep(10000); log.info("Thread {} do something", index); //歸還許可證 semaphore.release(); } catch (InterruptedException e) { log.error(e.getMessage()); } }); } } }
Exchanger
- public V exchange(V x)
- public V exchange(V x, long timeout, TimeUnit unit)
@Slf4j public class ExchangerDemo { private static final Integer THREAD_COUNT_NUM = 50; private static ExecutorService singleThreadPool; static { ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("jack").build(); singleThreadPool = new ThreadPoolExecutor( 10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); } public static void main(String[] args) { Exchanger<String> exchanger = new Exchanger<>(); singleThreadPool.execute(() -> { try { //A錄入記錄 String A = "A的記錄"; exchanger.exchange(A); } catch (Exception e) { log.error(e.getMessage()); } }); singleThreadPool.execute(() -> { try { //B錄入記錄 String B = "B的記錄"; String A = exchanger.exchange("B"); log.info("a和b的數據是否一致{},A錄入的是{},B錄入的是{}", A.equals(B), A, B); } catch (Exception e) { log.error(e.getMessage()); } }); } }