一個計數信號量。 在概念上,信號量維持一組許可證。 如果有必要,每個acquire()都會阻塞,直到許可證可用,然後才能使用它。 每個release()添加許可證,潛在地釋放阻塞的線程。 記得以前校招,一個公司對應很多面試的學生,因爲人數太多每次至多面試5個人,其他人只能等待,除非有人出來,等待的人才有機會進去,一般是排隊公平進去,但是大家爲了找工作都是搶着進去面試,大概是這麼個意思。等待就是acquire(),有人出來就是release(),Semaphore底層使用AQS實現
案例分析
public class SemaphoreDemo {
//添加3個許可證,採取公平策略,默認是分公平的
static Semaphore semaphore = new Semaphore(3, true);
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(50);
for (int i = 0; i < 10; i++) {
service.submit(new Task());
}
service.shutdown();
}
static class Task implements Runnable {
@Override
public void run() {
try {
//每個線程需要3個許可證才能進來,如果沒有3個就阻塞,直到有滿足的許可證可用
semaphore.acquire(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到了許可證");
// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName() + "釋放了許可證");
//釋放三個許可證
semaphore.release(3);
}
}
}
如果 semaphore.acquire(3);改爲 semaphore.acquire(4);那麼所有線程都會阻塞,因爲總共就只有三個許可證,或者 semaphore.release(3);改爲 semaphore.release(2);那麼第從二個線程開始所有線程都會阻塞,因爲執行需要3個許可證,但是第一個執行的線程只釋放了2個許可證
總之.release()操作happen-before acquire()操作,即釋放操作在獲取操作之前,釋放對獲取可見
此類共有兩個構造方法,兩個參數的構造可以選擇公平策略,默認是非公平的。
.release()與acquire()默認參數是1