簡介
Semaphore是一種在多線程環境下使用的設施,該設施負責協調各個線程,以保證它們能夠正確、合理的使用公共資源的設施,也是操作系統中用於控制進程同步互斥的量。
Semaphore是一種計數信號量,用於管理一組資源,內部是基於AQS的共享模式。它相當於給線程規定一個量從而控制允許活動的線程數。
Semaphore用於限制可以訪問某些資源(物理或邏輯的)的線程數目,他維護了一個許可證集合,有多少資源需要限制就維護多少許可證集合,假如這裏有N個資源,那就對應於N個許可證,同一時刻也只能有N個線程訪問。
舉個例子:
相信在學生時代都去餐廳打過飯,假如有3個窗口可以打飯,同一時刻也只能有3名同學打飯。第四個人來了之後就必須在外面等着,只要有打飯的同學好了,就可以去相應的窗口了。
一個線程獲取許可證就調用acquire方法,用完了釋放資源就調用release方法。
自定義Lock
public class SemaphoreTest {
public static void main(String[] args) {
final SemaphoreLock lock = new SemaphoreLock();
for (int i = 0; i < 2; i++) {
new Thread(()->{
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " get the lock.");
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName() + " release the lock.");
lock.unlock();
}
}).start();
}
}
static class SemaphoreLock{
private final Semaphore semaphore = new Semaphore(1);
public void lock() throws InterruptedException {
semaphore.acquire();
}
public void unlock() {
semaphore.release();
}
}
}
結果
Thread-0 get the lock.
Thread-0 release the lock.
Thread-1 get the lock.
Thread-1 release the lock.
跟synchronized的區別
- 可以看出最大的區別就是可以控制多個線程訪問資源,而不是隻用一個線程
構造方法
public Semaphore(int permits)
public Semaphore(int permits , boolean fair)
permits
:同一時間可以訪問資源的線程數目fair
:儘可能的保證公平
重要方法
public void acquire() throws InterruptedException
public void release()
acquire()
:獲取一個許可證,如果許可證用完了,則陷入阻塞。可以被打斷。release()
:釋放一個許可證
acquire(int permits)
public void release(int permits)
acquire多個時,如果沒有足夠的許可證可用,那麼當前線程將被禁用以進行線程調度,並且處於休眠狀態,直到發生兩件事情之一:
- 一些其他線程調用此信號量的一個release方法,當前線程旁邊將分配許可證,並且可用許可證的數量滿足此請求;
- 要麼一些其他線程interrupts當前線程。
release多個時,會使許可證增多,最終可能超過初始值
public boolean tryAcquire(int permits)
public boolean tryAcquire(int permits,
long timeout,
TimeUnit unit)
throws InterruptedException
- 嘗試去拿,拿到返回true
其他方法
public int availablePermits()
- 返回此信號量中當前可用的許可數。
protected Collection<Thread> getQueuedThreads()
public final int getQueueLength()
getQueuedThreads
返回正在阻塞的線程集合getQueueLength
返回阻塞獲取的線程數
public void acquireUninterruptibly()
public void acquireUninterruptibly(int permits)
- 可以
不被打斷
獲取許可證
public int drainPermits()
- 獲取當前全部的許可證