Java多線程之CountDownLatch、CyclicBarrier和Semaphore

轉自:http://www.liubey.org/countdownlatch_vs_cyclicbarrier/java


概述
app

CountDownLatch : 一個線程(或者多個), 等待另外N個線程完成某個事情以後才能執行。ide

CyclicBarrier : N個線程相互等待,任何一個線程完成以前,全部的線程都必須等待。測試

Semaphore:能夠控制某個資源可被同時訪問的個數,經過 acquire() 獲取一個許可,若是沒有就等待,而 release() 釋放一個許可。ui



舉例this

1:CountDownLatch

使用場景舉例:

體育課時老師拿着秒錶測試同窗的800米成績,那需求就是很簡單了,老師在起跑處組織你們一塊兒跑的瞬間按下秒錶計時開始,而後再終點處等待最後一個學生經過終點後開始聚集學生成績。pwa

API相關:

1)await(),阻塞等待,直到計數器清零
2)await(int timeout, TimeUnit unit),使線程阻塞,除非被中斷或者超過等待的最大時間
若是達到計數器清零,則await返回true,若是等待超過了最大的等待時間,則返回false
3)countDown(),計數器減一,當計數器清零時,await的線程被喚醒,線程繼續執行
4)getCount (),獲取當前計數器的大小線程


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;調試

public class TeacherWithStopwatch {
    public static final int NUMBER_OF_STUDENT = 10;
    public static final int NUMBER_OF_TEACHER = 1;
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CountDownLatch studentSignal = new CountDownLatch(NUMBER_OF_STUDENT);
        CountDownLatch teacherSignal = new CountDownLatch(NUMBER_OF_TEACHER);
        for (int i = 0; i < NUMBER_OF_STUDENT; i++) {
            executor.execute(new Student(i, studentSignal, teacherSignal));
        }
        try {
            System.out.println("各就各位!開跑!");
            teacherSignal.countDown();
            studentSignal.await();
            System.out.println("結果發送到彙報成績的系統");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}遊戲


    import java.util.concurrent.CountDownLatch;
public class Student implements Runnable {
    private int id;
    private CountDownLatch studentSignal;
    private CountDownLatch teacherSignal;
    public Student(int id, CountDownLatch studentSignal,
        CountDownLatch teacherSignal) {
        this.id = id;
        this.studentSignal = studentSignal;
        this.teacherSignal = teacherSignal;
    }
    @Override
    public void run() {
        try {
            teacherSignal.await();
            System.out.println("學生" + id + "起跑...");
            System.out.println("學生" + id + "到達終點。");
            studentSignal.countDown();
            System.out.println("學生" + id + "繼續幹其餘事情");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


2:CyclicBarrier

使用場景舉例:

有四個遊戲玩家玩遊戲,遊戲有三個關卡,每一個關卡必需要全部玩家都到達後才能容許通關。
其實這個場景裏的玩家中若是有玩家A先到了關卡1,他必須等待其餘全部玩家都到達關卡1時才能經過。
也就是說線程之間須要互相等待,這和CountDownLatch的應用場景有區別,
CountDownLatch裏的線程是到了運行的目標後繼續幹本身的其餘事情,而這裏的線程須要等待其餘線程後才能繼續完成下面的工做。

API相關:

public CyclicBarrier(int parties) 建立一個新的 CyclicBarrier,
它將在給定數量的參與者(線程)處於等待狀態時啓動,但它不會在啓動 barrier 時執行預約義的操做。
public CyclicBarrier(int parties, Runnable barrierAction) 建立一個新的 CyclicBarrier,
它將在給定數量的參與者(線程)處於等待狀態時啓動,並在啓動 barrier 時執行給定的屏障操做,
該操做由最後一個進入 barrier 的線程執行。
public int await() throws InterruptedException, BrokenBarrierException 在全部參與者都已經在此 barrier 上調用 await 方法以前,將一直等待。
public int await(long timeout,TimeUnit unit) throws InterruptedException, BrokenBarrierException,TimeoutException
在全部參與者都已經在此屏障上調用 await 方法以前將一直等待,或者超出了指定的等待時間。
public int getNumberWaiting() 返回當前在屏障處等待的參與者數目。此方法主要用於調試和斷言。
public int getParties() 返回要求啓動此 barrier 的參與者數目。
public boolean isBroken() 查詢此屏障是否處於損壞狀態。
public void reset() 將屏障重置爲其初始狀態。


public class GameBarrier {
    public static final int NUMBER_OF_PLAYERS = 4;
    public static void main(String[] args) {
    ExecutorService executor = Executors.newFixedThreadPool(NUMBER_OF_PLAYERS);
    CyclicBarrier barrier = new CyclicBarrier(NUMBER_OF_PLAYERS, new Runnable() {
        @Override
        public void run() {
            System.out.println("全部玩家經過第一關!");
        }
    });
    for (int i = 0; i < NUMBER_OF_PLAYERS; i++) {
        executor.execute(new Player(i, barrier));
    }
    executor.shutdown();
    }
}

public class Player implements Runnable {
    private CyclicBarrier cyclicBarrier;
    private int id;
    public Player(int id, CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
        this.id = id;
    }
    @Override
    public void run() {
        try {
            System.out.println("玩家" + id + "經過第一關...");
            cyclicBarrier.await();
            System.out.println("玩家" + id + "進入第二關...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
        e.printStackTrace();
        }
    }
}

3:Semaphore

使用場景舉例:

一個資源池只能同時五我的使用,那麼十我的來輪詢使用的狀況就是每一個人都先申請資源,使用完歸還於下一我的使用。

API相關:

構造器中的fairness爲true時,Semaphore保證各線程之後進先出(FIFO)的方式得到信號量。若是fairness爲false,則不保證這種順序,容許各線程之間的「討價還價」。

tryAcquire與release爲主要方法


public class Person implements Runnable {    private SemaphorePool pool;    private int id;    public Person(int id, SemaphorePool pool) {        this.pool = pool;        this.id = id;    }    @Override    public void run() {        try {            pool.applyResource();            System.out.println("人物" + id + "進入");            Thread.sleep(1000);            System.out.println("人物" + id + "離開");        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            pool.releaseResource();        }    }}public class SemaphorePool {    private Semaphore canExecuteCount = new Semaphore(5, true);    private static final int TRY_EXECUTE_TIMEOUT = 20;    public boolean applyResource() {        boolean canExecute = false;        try {            canExecute = canExecuteCount.tryAcquire(1, TRY_EXECUTE_TIMEOUT,                TimeUnit.SECONDS);        } catch (InterruptedException e) {}        return canExecute;    }    public void releaseResource() {        canExecuteCount.release(1);    }}public class TestSemaphore {    public static final int NUMBER_OF_PERSONS = 10;    public static final SemaphorePool pool = new SemaphorePool();    public static void main(String[] args) {        ExecutorService executor = Executors.newFixedThreadPool(NUMBER_OF_PERSONS);        for(int i=0;i<NUMBER_OF_PERSONS;i++) {            executor.execute(new Person(i, pool));        }        executor.shutdown();    }}

相關文章
相關標籤/搜索