CountDownLatch和CylicBarrier以及Semaphare你使用過嗎


CountDownLatch

是什么

CountDownLatch的字面意思:倒計時 門栓
它的功能是:讓一些線程阻塞直到另一些線程完成一系列操作后才喚醒。
它通過調用await方法讓線程進入阻塞狀態等待倒計時0時喚醒。
它通過線程調用countDown方法讓倒計時中的計數器減去1,當計數器為0時,會喚醒哪些因為調用了await而阻塞的線程。

  • 底層是使用AQS實現的

案例

假設老板開一個緊急會議,他先到會議室等着所有人簽到然后開始開會,可以使用CountDownLatch進行模擬。

 public static void main(String[] args) {
        CountDownLatch countDownLatch=new CountDownLatch(5);

        for (int i=1;i<=5;i++){
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"簽到!");
                countDownLatch.countDown();
            },"第"+i+"個人").start();
        }


        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("老板宣布人夠了開始開會!");
    }

運行結果:

//注意這里的簽到順序可以隨意
第1個人簽到!
第2個人簽到!
第3個人簽到!
第4個人簽到!
第5個人簽到!
老板宣布人夠了開始開會!

CyclicBarrier

是什么

CyclicBarrier [ˈsaɪklɪk] [ˈbæriər] 的字面意思:可循環使用的屏障 【柵欄】
它的功能是:讓一組線程到達一個屏障時被阻塞,知道最后一個線程到達屏障,所有被屏障攔截的線程才會繼續執行。
它通過調用await方法讓線程進入屏障,

  • 底層是通過ReentrantLock以及Condition中的await和signal實現
 /** The lock for guarding barrier entry */
    private final ReentrantLock lock = new ReentrantLock();
    /** Condition to wait on until tripped */
    private final Condition trip = lock.newCondition();

圖例

例子

還是上面的開會的例子,我們使用CyclicBarrier實現。

public static void main(String[] args) {
        CyclicBarrier cyclicBarrier=new CyclicBarrier(5,()->{
            System.out.println("老板宣布人夠了開始開會!!");
        });

        for (int i=1;i<=5;i++){
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName()+"簽到!");
                    cyclicBarrier.await(); //如果等待的線程數未到,這里將一直等待
                    //等線程數夠了下面語句將繼續執行......
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },"第"+i+"個人").start();
        }
    }

運行結果:

第1個人簽到!
第2個人簽到!
第3個人簽到!
第4個人簽到!
第5個人簽到!
老板宣布人夠了開始開會!!

Semaphor

是什么

Semaphor [ˈseməfɔːr] 信號量的意思;
它主要用於兩個目的:

  • 用於多個共享資源互斥使用。【也就是具有鎖的功能】
    一個停車場有多個停車位,這多個停車位對應汽車來說就是多個共享資源,Semaphor可以實現多個停車位和多個汽車之間的互斥。
  • 用於控制並發線程數。(就是控制同時得到共享資源的線程數量)
    在創建Semaphor時可以指定並發線程數,
    //permits :允許
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }
    //還可以指定是否為公平鎖
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
  • 信號量為1時 相當於獨占鎖 信號量大於1時相當於共享鎖。

例子

我們測試使用Semaphor實現控制線程並發訪問方法。

/**
 * 測試使用Semaphor信號量控制方法的訪問
 */
public class TestSemaphor {
    Semaphore semaphore=new Semaphore(5);
    /**
     * 假設並發只能為5個
     */
    public void pay(){
        try {
            //在 semaphore.acquire() 和 semaphore.release()之間的代碼,同一時刻只允許指定個數的線程進入!
            semaphore.acquire();
            System.out.println("這是支付的方法!");
            Thread.sleep(2000);
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

   public static void main(String[] args) {
        TestSemaphor ts=new TestSemaphor();
        for (int i=0;i<10;i++){
            new Thread(()->{
                ts.pay();
            },"線程"+i).start();
        }
    }
}

運行效果:

線程0這是支付的方法!
線程3這是支付的方法!
線程6這是支付的方法!
線程5這是支付的方法!
線程1這是支付的方法!

//注意這里是執行的暫停點

線程7這是支付的方法!
線程8這是支付的方法!
線程2這是支付的方法!
線程4這是支付的方法!
線程9這是支付的方法!

注意結果:10個線程分了兩批執行的,也就是說我們控制了訪問pay方法的線程數量,每次並發只能是5個!

CountDownlatch和CyclicBarrier以及Semaphor的區別是

  • CountDownLatch是做減法,CyclicBarrier是做加法,Semaphor的臨界資源可以反復使用

  • CountDownLatch不能重置計數,CycliBarrier提供的reset()方法可以重置計數,不過只能等到第一個計數結束。Semaphor可以重復使用。

  • CountDownLatch和CycliBarrier不能控制並發線程的數量,Semaphor可以實現控制並發線程的數量。

資源

更好的介紹


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM