Java多線程-新特征-信號量Semaphore


簡介
信號量(Semaphore),有時被稱為信號燈,是在多線程環境下使用的一種設施, 它負責協調各個線程, 以保證它們能夠正確、合理的使用公共資源。

概念
Semaphore分為單值和多值兩種,前者只能被一個線程獲得,后者可以被若干個線程獲得。

以一個停車場運作為例。為了簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛不受阻礙的進入,然后放下車攔,剩下的車則必須在入口等待,此后來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知后,打開車攔,放入一輛,如果又離開兩輛,則又可以放入兩輛,如此往復。

在這個停車場系統中,車位是公共資源,每輛車好比一個線程,看門人起的就是信號量的作用。

更進一步,信號量的特性如下:信號量是一個非負整數(車位數),所有通過它的線程(車輛)都會將該整數減一(通過它當然是為了使用資源),當該整數值為零時,所有試圖通過它的線程都將處於等待狀態。在信號量上我們定義兩種操作: Wait(等待) 和 Release(釋放)。 當一個線程調用Wait(等待)操作時,它要么通過然后將信號量減一,要么一直等下去,直到信號量大於一或超時。Release(釋放)實際上是在信號量上執行加操作,對應於車輛離開停車場,該操作之所以叫做“釋放”是因為加操作實際上是釋放了由信號量守護的資源。

在java中,還可以設置該信號量是否采用公平模式,如果以公平方式執行,則線程將會按到達的順序(FIFO)執行,如果是非公平,則可以后請求的有可能排在隊列的頭部。
JDK中定義如下:
Semaphore(int permits, boolean fair)
  創建具有給定的許可數和給定的公平設置的Semaphore。

Semaphore當前在多線程環境下被擴放使用,操作系統的信號量是個很重要的概念,在進程控制方面都有應用。Java並發庫Semaphore 可以很輕松完成信號量控制,Semaphore可以控制某個資源可被同時訪問的個數,通過 acquire() 獲取一個許可,如果沒有就等待,而 release() 釋放一個許可。比如在Windows下可以設置共享文件的最大客戶端訪問個數。

Semaphore實現的功能就類似廁所有5個坑,假如有10個人要上廁所,那么同時只能有多少個人去上廁所呢?同時只能有5個人能夠占用,當5個人中 的任何一個人讓開后,其中等待的另外5個人中又有一個人可以占用了。另外等待的5個人中可以是隨機獲得優先機會,也可以是按照先來后到的順序獲得機會,這取決於構造Semaphore對象時傳入的參數選項。單個信號量的Semaphore對象可以實現互斥鎖的功能,並且可以是由一個線程獲得了“鎖”,再由另一個線程釋放“鎖”,這可應用於死鎖恢復的一些場合。

 

package cn.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * 信號量 
 * 
 * @author 林計欽
 * @version 1.0 2013-7-25 下午02:03:40
 */
public class SemaphoreTest {
    public static void main(String[] args) {
        // 線程池
        ExecutorService exec = Executors.newCachedThreadPool();
        // 只能5個線程同時訪問
        final Semaphore semp = new Semaphore(5);
        // 模擬20個客戶端訪問
        for (int index = 0; index < 50; index++) {
            final int NO = index;
            Runnable run = new Runnable() {
                public void run() {
                    try {
                        // 獲取許可
                        semp.acquire();
                        System.out.println("Accessing: " + NO);
                        Thread.sleep((long) (Math.random() * 10000));
                        // 訪問完后,釋放
                        semp.release();
                        //availablePermits()指的是當前信號燈庫中有多少個可以被使用
                        System.out.println("-----------------" + semp.availablePermits()); 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            exec.execute(run);
        }
        // 退出線程池
        exec.shutdown();
    }
}
Accessing: 0
Accessing: 1
Accessing: 2
Accessing: 4
Accessing: 6
Accessing: 8
-----------------0
-----------------1
Accessing: 3
-----------------1
Accessing: 5
Accessing: 9
-----------------0
-----------------1
Accessing: 7
Accessing: 10
-----------------0
-----------------1
Accessing: 11
-----------------1
Accessing: 12
-----------------1
Accessing: 13
Accessing: 14
-----------------0
-----------------1
Accessing: 15
-----------------0
Accessing: 16
-----------------1
Accessing: 17
-----------------1
Accessing: 18
-----------------1
Accessing: 19
-----------------0
Accessing: 20
Accessing: 21
-----------------0
Accessing: 22
-----------------0
-----------------1
Accessing: 23
-----------------1
Accessing: 24
-----------------0
Accessing: 25
Accessing: 26
-----------------0
-----------------1
Accessing: 27
-----------------1
Accessing: 28
-----------------1
Accessing: 29
Accessing: 30
-----------------0
-----------------1
Accessing: 31
-----------------1
Accessing: 32
-----------------1
Accessing: 33
-----------------1
Accessing: 34
Accessing: 35
-----------------0
-----------------1
Accessing: 36
-----------------1
Accessing: 37
-----------------1
Accessing: 38
-----------------1
Accessing: 39
-----------------1
Accessing: 40
Accessing: 41
-----------------0
-----------------1
Accessing: 42
Accessing: 43
-----------------0
Accessing: 44
-----------------0
-----------------1
Accessing: 45
-----------------1
Accessing: 46
-----------------1
Accessing: 47
-----------------1
Accessing: 48
-----------------1
Accessing: 49
-----------------1
-----------------2
-----------------3
-----------------4
-----------------5

 


免責聲明!

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



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