java同步工具之Samaphore

     Samaphore可以維護當前訪問自身的線程個數,並提供了同步機制。使用Samaphore可以控制同時訪問資源的線程個數,例如,實現一個文件允許的併發訪問。

    從概念上講,信號量維護了一個許可集。如有必要,在許可可用前會阻塞每一個 acquire(),然後再獲取該許可。每個 release() 添加一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可對象,Semaphore 只對可用許可的號碼進行計數,並採取相應的行動。

     將信號量初始化爲 1,使得它在使用時最多隻有一個可用的許可,從而可用作一個相互排斥的鎖。這通常也稱爲二進制信號量,因爲它只能有兩種狀態:一個可用的許可,或零個可用的許可。按此方式使用時,二進制信號量具有某種屬性(與很多Lock 實現不同),即可以由線程釋放“鎖”,而不是由所有者(因爲信號量沒有所有權的概念)。在某些專門的上下文(如死鎖恢復)中這會很有用。

    此類的構造方法可選地接受一個公平 參數。當設置爲 false 時,此類不對線程獲取許可的順序做任何保證。特別地,闖入 是允許的,也就是說可以在已經等待的線程前爲調用acquire() 的線程分配一個許可,從邏輯上說,就是新線程將自己置於等待線程隊列的頭部。當公平設置爲 true 時,信號量保證對於任何調用獲取方法的線程而言,都按照處理它們調用這些方法的順序(即先進先出;FIFO)來選擇線程、獲得許可。注意,FIFO 排序必然應用到這些方法內的指定內部執行點。所以,可能某個線程先於另一個線程調用了acquire,但是卻在該線程之後到達排序點,並且從方法返回時也類似。還要注意,非同步的 tryAcquire 方法不使用公平設置,而是使用任意可用的許可。

通常,應該將用於控制資源訪問的信號量初始化爲公平的,以確保所有線程都可訪問資源。爲其他的種類的同步控制使用信號量時,非公平排序的吞吐量優勢通常要比公平考慮更爲重要。

    此類還提供便捷的方法來同時 acquire釋放多個許可。小心,在未將公平設置爲 true 時使用這些方法會增加不確定延期的風險。

    此類還提供便捷的方法來同時 acquire釋放多個許可。小心,在未將公平設置爲 true 時使用這些方法會增加不確定延期的風險。

   內存一致性效果:線程中調用“釋放”方法(比如 release())之前的操作 happen-before 另一線程中緊跟在成功的“獲取”方法(比如 acquire())之後的操作。

示例:

public class SemaphoreTest {
	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		final  Semaphore sp = new Semaphore(3);
		for(int i=0;i<10;i++){
			Runnable runnable = new Runnable(){
					public void run(){
					try {
						sp.acquire();
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					System.out.println("線程" + Thread.currentThread().getName() + 
							"進入,當前已有" + (3-sp.availablePermits()) + "個併發");
					try {
						Thread.sleep((long)(Math.random()*10000));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("線程" + Thread.currentThread().getName() + 
							"即將離開");					
					sp.release();
					//下面代碼有時候執行不準確,因爲其沒有和上面的代碼合成原子單元
					System.out.println("線程" + Thread.currentThread().getName() + 
							"已離開,當前已有" + (3-sp.availablePermits()) + "個併發");					
				}
			};
			service.execute(runnable);			
		}
	}

}

結果:

線程pool-1-thread-2進入,當前已有2個併發
線程pool-1-thread-1進入,當前已有2個併發
線程pool-1-thread-3進入,當前已有3個併發
線程pool-1-thread-2即將離開
線程pool-1-thread-2已離開,當前已有2個併發
線程pool-1-thread-5進入,當前已有3個併發
線程pool-1-thread-5即將離開
線程pool-1-thread-5已離開,當前已有2個併發
線程pool-1-thread-4進入,當前已有3個併發
線程pool-1-thread-3即將離開
線程pool-1-thread-3已離開,當前已有2個併發
線程pool-1-thread-7進入,當前已有3個併發
線程pool-1-thread-4即將離開
線程pool-1-thread-4已離開,當前已有2個併發
線程pool-1-thread-9進入,當前已有3個併發
線程pool-1-thread-7即將離開
線程pool-1-thread-7已離開,當前已有2個併發
線程pool-1-thread-8進入,當前已有3個併發
線程pool-1-thread-1即將離開
線程pool-1-thread-1已離開,當前已有2個併發
線程pool-1-thread-6進入,當前已有3個併發
線程pool-1-thread-6即將離開
線程pool-1-thread-6已離開,當前已有2個併發
線程pool-1-thread-10進入,當前已有3個併發
線程pool-1-thread-8即將離開
線程pool-1-thread-8已離開,當前已有2個併發
線程pool-1-thread-10即將離開
線程pool-1-thread-10已離開,當前已有1個併發
線程pool-1-thread-9即將離開
線程pool-1-thread-9已離開,當前已有0個併發

示例出自傳智播客 張孝祥 java多線程與併發庫高級應用。



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