併發編程之CountDownLatch,CyclicBarrier ,Semaphore

CountDownLatch

CountDownLatch 這個類在java.util.concurrent併發包下

這個類的作用使一個線程等到其他線程都執行完了在執行本線程、
CountDownLatch根據名字也可以看出來,它其實是一個計數器,數量是需要等待執行完線程的數量,沒執行完一個線程數量減1,當數量爲零的時候,表示所有需要等待的線程執行完畢了,那麼等待的的線程就可以繼續執行了!

說起來有點繞,其實一點也不復雜:

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

    ExecutorService service = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 5; i++){
        service.execute(() -> {
            System.out.println("開始執行" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("執行完畢" + Thread.currentThread().getName());
            latch.countDown();
        });
    }

    try {
        latch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("全部線程都執行完畢了,可以進行了");
}

初始化 CountDownLatch爲5,定義執行了5個線程,每個線程等待3秒之後調用latch.countDown();表示-1,當5個線程全部執行完了之後,被latch.await();阻塞的線程開始執行了,

結果如下:

開始執行pool-1-thread-1
開始執行pool-1-thread-2
開始執行pool-1-thread-3
開始執行pool-1-thread-4
開始執行pool-1-thread-5
執行完畢pool-1-thread-2
執行完畢pool-1-thread-3
執行完畢pool-1-thread-1
執行完畢pool-1-thread-4
執行完畢pool-1-thread-5
全部線程都執行完畢了,可以進行了

CountDownLatch 還有個重載的await()方法:await(long timeout, TimeUnit unit) 表示的是超時時間,如果等到了規定的時間,其他的線程還沒有執行完的話就不等了

CyclicBarrier

CyclicBarrier這個類也在java.util.concurrent併發包下
CyclicBarrier的作用是等到所有的線程同時到達指定的狀態後在同時執行,比如:

 CyclicBarrier barrier = new CyclicBarrier(5);

    ExecutorService service = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 5; i++){
        service.submit(()->{
            System.out.println(Thread.currentThread().getName() + "正在執行。。。。");
            try {
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() +  " 已經執行完了,等待其他線程執行完畢");
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "後續的任務開始執行");
        });
    }
}

結果如下:

pool-1-thread-2正在執行。。。。
pool-1-thread-1正在執行。。。。
pool-1-thread-3正在執行。。。。
pool-1-thread-5正在執行。。。。
pool-1-thread-4正在執行。。。。
pool-1-thread-5 已經執行完了,等待其他線程執行完畢
pool-1-thread-2 已經執行完了,等待其他線程執行完畢
pool-1-thread-1 已經執行完了,等待其他線程執行完畢
pool-1-thread-3 已經執行完了,等待其他線程執行完畢
pool-1-thread-4 已經執行完了,等待其他線程執行完畢
pool-1-thread-3後續的任務開始執行
pool-1-thread-2後續的任務開始執行
pool-1-thread-4後續的任務開始執行
pool-1-thread-5後續的任務開始執行
pool-1-thread-1後續的任務開始執行

CyclicBarrier 有兩個構造方法:

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}
public CyclicBarrier(int parties) {
    this(parties, null);
}

parties表示的是要等到多少個線程達到指定的狀態之後去執行
Runnable barrierAction 第二個參數表示的時候線程們都達到了指定的狀態之後,先執行barrierAction,然後在同時執行。就是都達到了指定的狀態,然後進行一些額外的操作,比如:

public static void main(String[] args) {

    CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
        @Override
        public void run() {
            System.out.println("需要進行一些別的操作!");
        }
    });

    ExecutorService service = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 5; i++){
        service.submit(()->{
            System.out.println(Thread.currentThread().getName() + "正在執行。。。。");
            try {
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() +  " 已經執行完了,等待其他線程執行完畢");
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "後續的任務開始執行");
        });
    }
}

結果如下:

pool-1-thread-1正在執行。。。。
pool-1-thread-2正在執行。。。。
pool-1-thread-3正在執行。。。。
pool-1-thread-4正在執行。。。。
pool-1-thread-5正在執行。。。。
pool-1-thread-3 已經執行完了,等待其他線程執行完畢
pool-1-thread-4 已經執行完了,等待其他線程執行完畢
pool-1-thread-2 已經執行完了,等待其他線程執行完畢
pool-1-thread-1 已經執行完了,等待其他線程執行完畢
pool-1-thread-5 已經執行完了,等待其他線程執行完畢
需要進行一些別的操作!
pool-1-thread-5後續的任務開始執行
pool-1-thread-3後續的任務開始執行
pool-1-thread-4後續的任務開始執行
pool-1-thread-1後續的任務開始執行
pool-1-thread-2後續的任務開始執行

barrier.await();還有另外一個重載的方法:

public int await(long timeout, TimeUnit unit)

和CountDownLatch類似,定義一個超時機制,表示如果到了時間可以不用等到所有的線程都到達某個狀態,就開始執行。

需要注意是的是CyclicBarrier ,是可以重複使用的,要不讓怎麼會有Cyclic呢。就是當一輪線程執行完了之後,你可以繼續調用awiat,進行新一輪的等待執行操作,但是CountDownLatch不可以!
CountDownLatch和CyclicBarrier側重點不同,CountDownLatch側重的是某些任務都執行完了,然後進行後續的操作。而CyclicBarrier表示的是當所有的線程都相互等待到某一個狀態之後進行同時進行後續的操作!

Semaphore

Semaphore字面意思是信號量,表示的是同時有多少個線程開始執行:

ExecutorService pool = Executors.newFixedThreadPool(10);

Semaphore semaphore = new Semaphore(3);

for (int i = 0; i < 5; i++){
    pool.submit(()->{
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + "獲得線程的執行權");
            Thread.sleep(3000);
            System.out.println(Thread.currentThread().getName() + "執行完畢");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

結果:

pool-1-thread-1獲得線程的執行權
pool-1-thread-2獲得線程的執行權
pool-1-thread-3獲得線程的執行權
pool-1-thread-1執行完畢
pool-1-thread-3執行完畢
pool-1-thread-2執行完畢
pool-1-thread-4獲得線程的執行權
pool-1-thread-5獲得線程的執行權
pool-1-thread-5執行完畢
pool-1-thread-4執行完畢

因爲semaphore初始化指定爲3,表示只能有三個線程同時執行,所以只有等到線程執行完調用了release方法,第4第5個線程纔可以執行。

再小的進步,乘以356天也會變的偉大!

歡迎關注我的公衆號: 北風中獨行的蝸牛
在這裏插入圖片描述

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