1. 程式人生 > >java併發程式設計之Semaphore(訊號量)的用法

java併發程式設計之Semaphore(訊號量)的用法

Semaphore類其實就是synchronized關鍵字的升級版,這個類主要作用就是控制執行緒併發的數量,而在這方面synchronized就有點力不足了,接下來我們就開始先了解一下Semaphore的一些常用方法就注意細節。

在new 這個類的時候需要給這個類傳遞一個引數permits,這個引數是整數型別,這個引數的意思是同一時間內,最多允許多少個執行緒同時執行acquire方法和release方法之間的程式碼,如果方法acquire沒有引數則預設是一個許可。下面我們用程式碼進行驗證。

Semaphore又稱訊號量,是作業系統中的一個概念,在Java併發程式設計中,訊號量控制的是執行緒併發的數量。

public Semaphore(int permits)

其中引數permits就是允許同時執行的執行緒數目;

下面先看一個訊號量實現單執行緒的例子,也就是permits=1:

package concurrent.semaphore;

import java.util.concurrent.Semaphore;

public class Driver {
    // 控制執行緒的數目為1,也就是單執行緒
    private Semaphore semaphore = new Semaphore(1);

    public void driveCar() {
        try {
            // 從訊號量中獲取一個允許機會
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
            // 釋放允許,將佔有的訊號量歸還
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package concurrent.semaphore;

public class Car extends Thread{
    private Driver driver;

    public Car(Driver driver) {
        super();
        this.driver = driver;
    }

    public void run() {
        driver.driveCar();
    }
}
public class Run {
    public static void main(String[] args) {
        Driver driver = new Driver();
        for (int i = 0; i < 5; i++) {
            (new Car(driver)).start();
        }
    }
}

執行結果:

Thread-0 start at 1482664517179
Thread-0 stop at 1482664518179
Thread-3 start at 1482664518179
Thread-3 stop at 1482664519179
Thread-1 start at 1482664519179
Thread-1 stop at 1482664520179
Thread-4 start at 1482664520179
Thread-4 stop at 1482664521180
Thread-2 start at 1482664521180
Thread-2 stop at 1482664522180

從輸出可以看出,改輸出與單執行緒是一樣的,執行完一個執行緒,再執行另一個執行緒。

如果訊號量大於1呢,我們將訊號量設為3:

public class Driver {
    // 將訊號量設為3
    private Semaphore semaphore = new Semaphore(3);

    public void driveCar() {
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

輸出:

Thread-0 start at 1482665412515
Thread-3 start at 1482665412517
Thread-1 start at 1482665412517
Thread-3 stop at 1482665413517
Thread-0 stop at 1482665413517
Thread-4 start at 1482665413517
Thread-2 start at 1482665413517
Thread-1 stop at 1482665413518
Thread-4 stop at 1482665414517
Thread-2 stop at 1482665414517

從輸出的前三行可以看出,有3個執行緒可以同時執行,三個執行緒同時執行的時候,第四個執行緒必須等待前面有一個要完成,才能執行第四個執行緒啟動。

當然也可以用acquire動態地新增permits的數量,它表示的是一次性獲取許可的數量,比如:

public class Driver {
    // 訊號量共10個
    private Semaphore semaphore = new Semaphore(10);

    public void driveCar() {
        try {
            // 每次獲取3個
            semaphore.acquire(3);
            System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上述程式碼中總的訊號量除以每次獲取的許可數即10/3=3,就是說可以允許3個執行緒一起執行。

我們可以用public int availablePermits()檢視現在可用的訊號量:

public class SemaphoreAvaliablePermits {
    public static void main(String[] args) {
        try{
            Semaphore semaphore = new Semaphore(10);
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.acquire();
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.acquire(2);
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.acquire(3);
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.acquire(4);
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.release();
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.release(2);
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.release(3);
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.release(4);
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

輸出:

Semaphore available permits: 10
Semaphore available permits: 9
Semaphore available permits: 7
Semaphore available permits: 4
Semaphore available permits: 0
Semaphore available permits: 1
Semaphore available permits: 3
Semaphore available permits: 6
Semaphore available permits: 10

還有一個方法public int drainPermits(),這個方法返回即可所有的許可數目,並將許可置0:

public class SemaphoreDrainPermits {
    public static void main(String[] args) {
        try{
            Semaphore semaphore = new Semaphore(10);
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            semaphore.acquire();
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            System.out.println("Semaphore drain permits" + semaphore.drainPermits());
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
            System.out.println("Semaphore drain permits" + semaphore.drainPermits());
            System.out.println("Semaphore available permits: " + semaphore.availablePermits());
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

輸出:

Semaphore available permits: 10
Semaphore available permits: 9
Semaphore drain permits9
Semaphore available permits: 0
Semaphore drain permits0
Semaphore available permits: 0

相關推薦

java併發程式設計Semaphore訊號用法

Semaphore類其實就是synchronized關鍵字的升級版,這個類主要作用就是控制執行緒併發的數量,而在這方面synchronized就有點力不足了,接下來我們就開始先了解一下Semaphore的一些常用方法就注意細節。 在new 這個類的時候需要給這個類傳遞一個引

android 驅動中的併發和競爭——semaphore訊號

在現代的Linux系統中,有非常多的併發源,因此而帶來競爭情況,競爭來源於不同的程序對同一共享資源的同時存取。而Linux系統提供了一系列的處理併發和資源競爭的方法,下面介紹幾個: 1、semaphore(訊號量) 訊號量的使用類似於一對P、V函式,通常一個想進入臨界區的程

JAVA併發程式設計——Semaphore訊號

控制併發執行緒數的Semaphore Semaphore(訊號量)是用來控制同時訪問特定資源的執行緒數量,它通過協調各個執行緒,以保證合理的使用公共資源。應用場景Semaphore可以用於做流量控制,特別是公用資源有限的應用場景,比如資料庫連線。假如有一個需求,

Java併發程式設計Semaphore(二)

一.介紹 Semaphore是一種在多執行緒環境下使用的設施,該設施負責協調各個執行緒,以保證它們能夠正確、合理的使用公共資源的設施,也是作業系統中用於控制程序同步互斥的量。Semaphore是一種計數訊號量,用於管理一組資源,內部是基於AQS的共享模式。它相當於給執行緒規定一個量從而控制允

併發:控制併發執行緒數的Semaphore訊號

Semaphore是用來控制同時訪問特定資源的執行緒數量,他通過協調各個執行緒,以保證合理的使用公平資源。 多年以來,我都覺得從字面上很難理解Semaphore所表達的含義,只能把他比作是控制流量的紅綠燈。比如xx馬路要限制流量,只允許同時有一百兩車在這條路上行使,其他的都必須在路口等待,所以前

Java併發閉鎖/柵欄/訊號併發模型和鎖

threadLocal能夠為每一個執行緒維護變數副本,常用於在多執行緒中用空間換時間     程序死鎖:程序死鎖,指多個程序迴圈等待他方佔有的資源而一直等待下去的局面;  程序活鎖:執行緒1,2需要同時佔有a,b才可以,1佔有a,2佔有b,為了避免死鎖,

Java併發閉鎖/柵欄/訊號

一、Java多執行緒總結: 描述執行緒的類:Runable和Thread都屬於java.lang包。 內建鎖synchronized屬於jvm關鍵字,內建條件佇列操作介面Object.wait()/

Java 併發程式設計 volatile

都是快取惹的禍害 快取一致性協議: 當某個CPU核心寫資料時,如果發現這個變數為共享變數,即在其他CPU快取中也有副本,就會通知其他CPU將改變數的快取置為無效, 其他CPU需要從記憶體重新讀取。 MESI 的狀態 案例: 資料有

程序:程序同步——LockSemaphore訊號、Event事件

目錄 鎖 —— multiprocess.Lock 訊號量 —— multiprocess.Semaphore(瞭解) 事件 —— multiprocess.Event(瞭解) 鎖 —— multiprocess.Lock   當多個程序使用同一份資料資源的時候,就會引發資料

執行緒:Lock互斥鎖、RLock 遞迴鎖Semaphore訊號、Event事件、Condition條件、Timer定時器、queue佇列

目錄 一、鎖 1)同步鎖 2)死鎖與遞迴鎖 二、訊號量 三、事件 四、條件 五、定時器 六、執行緒佇列 一、鎖 1)同步鎖 #同步鎖的引用 from threading import Thread,Lock import os,time def wor

c# Semaphore訊號

http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813635.html http://hi.baidu.com/bloodcrystal/blog/item/00ebd7f9da5aadd2b58f317c.h

JUC 中提供的限流利器-Semaphore訊號

在 JUC 包下,有一個 Semaphore 類,翻譯成訊號量,Semaphore(訊號量)是用來控制同時訪問特定資源的執行緒數量,它通過協調各個執行緒,以保證合理的使用公共資源。Semaphore 跟鎖(synchronized、Lock)有點相似,不同的地方是,鎖同一時刻只允許一個執行緒訪問某一資源,而

java架構多執行緒JUC併發程式設計Semaphore訊號、CountDownLatch、CyclicBarrier柵欄、Executors執行緒池

上期回顧:   上次部落格我們主要說了我們juc併發包下面的ReetrantLock的一些簡單使用和底層的原理,是如何實現公平鎖、非公平鎖的。內部的雙向連結串列到底是什麼意思,prev和next到底是什麼,為什麼要引入heap和tail來值向null的Node節點。高併發時候是如何保證state來記錄重入鎖的

Java併發程式設計(8)-Semaphore訊號解讀

文章目錄 一、Semaphore訊號量 1.1、什麼是訊號量 1.2、訊號量在併發程式設計中的作用 二、Semaphore類簡單解讀 2.1、構造方法解讀

Java併發程式設計實戰————Semaphore訊號的使用淺析

引言 本篇部落格講解《Java併發程式設計實戰》中的同步工具類:訊號量 的使用和理解。 從概念、含義入手,突出重點,配以程式碼例項及講解,並以生活中的案例做類比加強記憶。 什麼是訊號量 Java中的同步工具類訊號量即計數訊號量(Counting Semaphore),是

Java併發程式設計鎖機制ReentrantLock)重入鎖

最近在忙公司的專案,現在終於有時間來寫部落格啦~開心開心 前言 通過前面的文章,我們已經瞭解了AQS(AbstractQueuedSynchronizer)內部的實現與基本原理。現在我們來了解一下,Java中為我們提供的Lock機制下的鎖實現--ReentrantLock(重入鎖),閱讀該篇文章

Java併發程式設計鎖機制ReentrantReadWriteLock讀寫鎖

前言 在前面的文章中,我們講到了ReentrantLock(重入鎖),接下來我們講ReentrantReadWriteLock(讀寫鎖),該鎖具備重入鎖的可重入性、可中斷獲取鎖等特徵,但是與ReentrantLock不一樣的是,在ReentrantReadWriteLock中,維護了一對鎖,一個讀鎖一個寫鎖

Java併發程式設計CountDownLatch、CyclicBarrier和Semaphore

在java 1.5中,提供了一些非常有用的輔助類來幫助我們進行併發程式設計,比如CountDownLatch,CyclicBarrier和Semaphore,今天我們就來學習一下這三個輔助類的用法。 CountDownLatch   CountDownLa

java 併發程式設計學習筆記 併發基礎

                                              併發基礎 併發小測試 java.util.concurrent.Semaphore 類 public class SemTest { /** * Se

java 併發程式設計學習筆記 基礎框架搭建和併發模擬工具,程式碼

                                基礎框架搭建和併發模擬工具,程式碼 (1)基礎框架搭建 (2)併發模擬 (3)CountDownLatch  通常用來 保證 幾個執行緒執行完成之後,再執行其他的程式碼 Semaphore