概述
Semaphore 也叫信号量,在 JDK1.5 被引入,可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。
Semaphore 内部维护了一个计数器,其值为可以访问的共享资源的个数.一个线程要访问共享资源,先获得信号量,如果信号量的计数器值大于 1 ,意味着有共享资源可以访问,则使其计数器值减去 1 ,再访问共享资源.
如果计数器值为 0 ,线程进入休眠.当某个线程使用完共享资源后,释放信号量,并将信号量内部的计数器加 1 ,之前进入休眠的线程将被唤醒并再次试图获得信号量.
访问特定资源前,必须使用 acquire 方法获得许可,如果许可数量为 0 ,该线程则一直阻塞,直到有可用许可.
访问资源后,使用 release 释放许可.
Semaphore 和 ReentrantLock 类似,获取许可有公平策略和非公平许可策略,默认情况下使用非公平策略.
API
// 构造方法
// permits 初始数量
public Semaphore(int permits)
# fair 是否使用公平策略,true: 公平策略,采用先来先用的算法,false: 非公平策略,完全随机,默认使用非公平策略.
public Semaphore(int permits, boolean fair)
// acquire 函数
// 申请一个资源
public void acquire() throws InterruptedException
// 申请 permits 个资源
public void acquire(int permits) throws InterruptedException
// acquireUninterruptibly 函数
// 线程在申请资源过程中被打断,依然会继续申请,只不过获取资源的时间可能会有所变化.
public void acquireUninterruptibly()
public void acquireUninterruptibly(int permits)
// tryAcquire 函数
// 申请一个资源,如果当前有可用资源,立即返回 true ,否则立即返回 false
public boolean tryAcquire()
// 申请一个资源,指定一个超时时间,如果当前可以资源数量足够,立即返回 true ,否则最多等待给定的时间,如果时间到还是未能获取资源,则返回 false ;如果等待过程中线程被打断,抛出 InterruptedException 异常
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
// 和 tryAcquire() 一样,只是申请 permits 个资源
public boolean tryAcquire(int permits)
// 和 tryAcquire(long timeout, TimeUnit unit) 一样,只是申请 permits 个资源
public boolean tryAcquire(int permits, long timeout,TimeUnit unit) throws InterruptedException
// release 函数
// 释放一个资源
public void release()
// 释放 permits 个资源
public void release(int permits)
// availablePermits 函数
// 获取当前可用的资源数量
public int availablePermits()
// drainPermits 函数
// 申请当前所有可用的资源
public int drainPermits()
// reducePermits 函数
// 禁止某些资源不可用, reduction 表示禁止的数量
protected void reducePermits(int reduction)
// isFair 函数
// 判断当前的信号量是采用什么类型的策略
// true 表示采用的是公平策略,返回 false 表示采用非公平策略
public boolean isFair()
// hasQueuedThreads 函数
// 判断是否有现成正在等待申请资源, true: 有现成正在等待申请资源 false: 没有
public final boolean hasQueuedThreads()
// getQueueLength 函数
// 返回正在等待申请资源的线程的数量
public final int getQueueLength()
// getQueuedThreads 函数
// 返回当前正在等待申请资源的线程集合
protected Collection<Thread> getQueuedThreads()
使用
ExecutorService executorService = Executors.newCachedThreadPool();
// 资源最多可被10个线程并发访问
Semaphore semaphore = new Semaphore(10);
for (int i = 0; i < 20; i++) {
final int threadnum = i;
executorService.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("current thread" + Thread.currentThread().getName());
// 获取许可
semaphore.acquire(1);
// 释放许可
semaphore.release(1);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
// 如果不 shutdown 工程不会结束
executorService.shutdown();