简介
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()
- 获取当前全部的许可证