CountDownLatch,CyclicBarrier,Semaphore,Exchanger

  • 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());
            }
        });
        
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章