併發編程之信號量Semaphore

      在以前的操作系統學習中,爲了實現進程的同步,需要設置信號量執行P、V操作來實現。在Java中,線程之間的同步也是使用信號量Semaphore類來實現的。線程訪問臨界資源(需互斥訪問的那段代碼)的時候,如果信號量(計數器)大於0,則允許進入臨界資源,若信號量小於等於0,則線程阻塞等待另外的線程釋放臨界資源。Java 併發庫的Semaphore 可以很輕鬆完成信號量控制,Semaphore 通常用於限制可以訪問某些資源(物理或邏輯的)的線程數目。通過 acquire() 獲取一個許可,如果沒有就等待,而 release() 釋放一個許可。比如在Windows下可以設置共享文件的最大客戶端訪問個數。

Semaphore概述
---通常把一個非負整數稱爲Semaphore,表示爲S.
    S可以理解爲可用的資源數量.這裏不涉及進程問題,所以就假定S>=0.
---S實現的同步機制表示爲PV原語操作
    P(S):若S=0,線程進入等待隊列;否則,—S;
    V(S):++S,喚醒處於等待中的線程.

     信號量的特性如下:信號量是一個非負整數,所有通過它的線程都會將該整數減一,當該整數值爲零時,所有試圖通過它的線程都將處於等待狀態。在信號量上我們定義兩種操作: Acquire(等待) 和 Release(釋放)。當一個線程調用Acquire(等待)操作時,它要麼通過然後將信號量減一,要麼一直等下去,直到信號量大於一或超時。Release(釋放)實際上是在信號量上執行加操作,加操作實際上是釋放了由信號量守護的資源。

    在java中,還可以設置該信號量是否採用公平模式,如果以公平方式執行,則線程將會按到達的順序(FIFO)執行,如果是非公平,則可以後請求的有可能排在隊列的頭部。
    1、Semaphore(int permits, boolean fair):創建具有給定的許可數和給定的公平設置的Semaphore。在該構造函數中,permits指定了計數器的初始值,如果permits=1,則說明在某個時間間隔之內,只允許一個線程訪問臨界資源,默認情況下(fair默認爲false,即不採用公平策略),等待線程以隨機順序獲取臨界資源(當permits>0時),若將fair設置爲true,則採用公平策略,等待線程已他們要求的訪問順序獲取臨界資源。
    2、Semaphore類中,請求獲取臨界資源的方法如下所示:tryAcquire、acquire;
    3、Semaphore類中,請求獲取臨界資源的方法如下所示:release;

示例程序:

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class Bank {
	private final static int COUNT = 100;
	private final static Semaphore semaphore = new Semaphore(3, true);

	public static void main(String[] args) {
		for (int i = 0; i < COUNT; i++) {
			final int count = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						// 沒有可用的資源就等待一段時間,如果在該時間內仍未獲取到所需要的資源semaphore,就返回false
						// 這裏只申請一個,如果申請多個需要調用其他的請求方法
						if (semaphore.tryAcquire(10, TimeUnit.MILLISECONDS)) {
							try {
								Teller.getService(count);
							} finally {
								// 釋放所獲取到的資源semaphore
								semaphore.release();
							}
						}
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
		}
	}
}

class Teller {
	static public void getService(int i) {
		System.out.println("serving:" + i);
		try {
			Thread.sleep((long) (Math.random() * 100));
		} catch (InterruptedException e) {
		}
	}
}

運行結果(一種)

serving:10
serving:0
serving:11
serving:9
serving:8

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