前言:信號量從概念上講,信號量維護了一個許可集。如有必要,在許可可用前會阻塞每一個 acquire()
,然後再獲取該許可。每個 release()
添加一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可對象,Semaphore
只對可用許可的號碼進行計數,並採取相應的行動。能併發控制訪問cpu線程的數目。實際就是可以允許多個線程併發訪問共享資源。
一,構造方法
第二個構造方法提供了是否公平
當設置爲false時,那麼這個類對線程獲取許可的順序做任何保證,也就是說可以在已經等待的線程前爲調用 acquire()
的線程分配一個許可,從邏輯上說,就是新線程將自己置於等待線程隊列的頭部。因爲內部實現也是基於AQS組件的。
當設置爲true時,信號量保證對於任何調用 acquire()
方法的線程而言,都按照處理它們調用這些方法的順序(即先進先出;FIFO)來選擇線程、獲得許可。
二,常用的幾個方法
注意,acquire()方法和acquireUninteruptibly()雖然能使線程在獲得許可前被阻塞,但不能中斷響應(對於synchronized,一個線程在等待鎖,一般會有兩種情況,要麼線程獲得鎖繼續執行,要麼線程一直處於等待鎖的狀態,但是重入鎖會提供另外一種可能,在線程等待鎖的過程中,程序可以取消線程對鎖的請求)
簡單實例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreDemo {
public static class SemapDemo implements Runnable{
//創建許可數爲5 的
final Semaphore semaphore = new Semaphore(5);
@Override
public void run() {
try {
semaphore.acquire();//獲得許可
System.out.println(Thread.currentThread().getId() + "獲得許可!");
Thread.sleep(1000);
if (semaphore.hasQueuedThreads()){
System.out.println("線程池大約還有"+semaphore.getQueueLength()+"個線程在等待");
}
semaphore.release(5);//釋放5個許可
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(20);//創建線程池
final SemapDemo semapDemo = new SemapDemo();
for (int i = 0; i <20 ; i++) {
pool.submit(semapDemo);//提交線程到線程池
}
pool.shutdown();
}
}
從運行結果來看,設置5個許可,那麼在線程提交的時候首先會有5 個線程持有許可,同時提起來,其他的線程就處於等待的狀態。當釋放5個許可後就會又有五個線程獲得許可。