java多線程系列:Semaphore和Exchanger

來源:互聯網
上載者:User

標籤:mit   rev   cut   tor   sys   its   map   BMI   進入   

本篇文章將介紹Semaphore和Exchanger這兩個並發工具類。

Semaphore

訊號量(英語:Semaphore)又稱為訊號標,是一個同步對象,用於保持在0至指定最大值之間的一個計數值。當線程完成一次對該semaphore對象的等待(wait)時,該計數值減一;當線程完成一次對semaphore對象的釋放(release)時,計數值加一。當計數值為0,則線程等待該semaphore對象不再能成功直至該semaphore對象變成signaled狀態。semaphore對象的計數值大於0,為signaled狀態;計數值等於0,為nonsignaled狀態.

semaphore對象適用於控制一個僅支援有限個使用者的共用資源,是一種不需要使用忙碌等待(busy waiting)的方法。 ----取自維基百科

Semaphore思想在分布式中也有應用,分布式限流就是典型的案例。現在舉個小例子來使用Semaphore

案例

在等公交時,遇到人多的時候經常需要排隊或者擠進去。

解決方案

利用Semaphore初始化5個許可,每次只能有5個玩家進入,當有玩家退出時,其他玩家才能進入。

先介紹下Semaphore的建構函式和一些方法吧。

Semaphore建構函式
public Semaphore(int permits);public Semaphore(int permits, boolean fair);

第一個參數permits表示初始化的許可數量,第二個參數表示是否是公平的。

使用Semaphore(int permits)建構函式時,預設使用非公平的

Semaphore常用方法
public void acquire();public void release();

acquire方法取得許可,release方法表示釋放許可。

註:如果多次調用release方法,會增加許可。例如,初始化許可為0,這時調用了兩個release方法,Semaphore的許可便會變成2

這兩個是最常用的方法,其他的還有acquire相關的方法tryAcquire和acquireUninterruptibly這裡就不介紹了。

代碼玩家類

定義一個實現Runnable介面的玩家類

public class Player implements Runnable{    private String playerName;    private Semaphore semaphore;    public Player(String playerName, Semaphore semaphore) {        this.playerName = playerName;        this.semaphore = semaphore;    }    @Override    public void run() {        try {            semaphore.acquire();            System.out.println(playerName+"進入,時間:"+LocalTime.now());            Thread.sleep((long) (3000 * Math.random()));        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            System.out.println(playerName+"退出");            semaphore.release();        }    }}

通過建構函式Player傳入玩家名稱和Semaphore對象,run方法中先調用acquire方法取得許可,然後睡眠隨機時間,最後在finally中調用release方法釋放許可。

測試類別

先來使用非公平的看看效果,使用非公平的就好比平時的擠公交,誰先在車門口誰先進。如(來源於網路)

現在來看看測試代碼

public static void main(String[] args) throws IOException {    Semaphore semaphore = new Semaphore(5);    //Semaphore semaphore = new Semaphore(5,true);    ExecutorService service = Executors.newCachedThreadPool();    //類比100個玩家排隊    for (int i = 0; i < 100; i++) {        service.submit(new Player("玩家"+i,semaphore));    }    //關閉線程池    service.shutdown();    //判斷線程池是否中斷,沒有則迴圈查看當前排隊總人數    while (!service.isTerminated()){        System.out.println("當前排隊總人數:"+semaphore.getQueueLength());        try {            Thread.sleep(5000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

如果要切換成公平方式只需將上面初始化Semaphore改為下面的代碼即可

Semaphore semaphore = new Semaphore(5,true);
Exchanger

Exchanger主要用於線程間的資料交換。 它提供了一個同步點在這個同步點,兩個線程可以交換資料

這裡寫了個兩個線程互相交換資料的簡單例子,下面ExchangerRunnable在run方法中調用exchange方法將自己的資料傳過去。

public class ExchangerRunnable implements Runnable {    private Object data;    private String name;    private Exchanger exchanger;    public ExchangerRunnable(String name, Exchanger exchanger, Object data) {        this.exchanger = exchanger;        this.name = name;        this.data = data;    }    public void run() {        try {            Object previous = this.data;            this.data = this.exchanger.exchange(previous);            System.out.println("名稱:" + name + " 之前資料:" + previous + " ,交換之後資料:" + this.data);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

接下來看看測試代碼

public class Case {    private static final Exchanger exchanger = new Exchanger();    private static ExecutorService service = Executors.newFixedThreadPool(2);    public static void main(String[] args) {        service.submit(new ExchangerRunnable("1", exchanger, "A"));        service.submit(new ExchangerRunnable("2", exchanger, "B"));        service.shutdown();    }}

定義了只包含兩個線程的線程池,然後建立提交兩個ExchangerRunnable的類

  1. 線程名稱為1的未經處理資料時A
  2. 線程名稱為2的未經處理資料時B

運行測試代碼,會得到如下結果

名稱:2 之前資料:B ,交換之後資料:A名稱:1 之前資料:A ,交換之後資料:B

案例原始碼地址:https://github.com/rainbowda/learnWay/tree/master/learnConcurrency/src/main/java/com/learnConcurrency/utils

歡迎fork、Star、Issue等,謝謝

java多線程系列:Semaphore和Exchanger

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.