Semaphore 控制访问特定资源的线程数量,新建规定数量的许可证,获得许可证可以继续执行,未获得需要阻塞,执行完成归还许可证,这样其余的线程(未获得许可证)才可以执行。例如:Semaphore用于流量控制,例如只有10个数据库连接,可以用Semaphore控制只有10个线程访问数据库,这样就不会报错无法获取数据库连接。
1. Semaphore的部分方法
方法 | 描述 |
public Semaphore(int permits) | 构造函数:设置许可证数permits。 |
public Semaphore(int permits, boolean fair) | 设置许可证数permits, fair 为 true 使用先进先出的公平策略,false则不公平。 |
public void acquire() | 获取许可证。 |
public void acquireUninterruptibly() | 不可中断的获取许可证。 |
public boolean tryAcquire() | 尝试获取许可证,没有许可证不阻塞 |
public boolean tryAcquire(long timeout, TimeUnit unit) | 等待一定时间,一直没有获得许可证不再阻塞 |
public void release() | 归还许可证 |
public void acquire(int permits) | 获取给定数量的许可证 |
public void release(int permits) | 归还给定数量的许可证 |
public final boolean hasQueuedThreads() | 是否有线程在等待 |
public final int getQueueLength() | 等待线程的数量 |
protected Collection<Thread> getQueuedThreads() | 返回所有等待许可的线程集合 |
public int availablePermits() | 剩余许可证 |
2. 测试代码
许可证数量初始为 3 。
private static Semaphore semaphore = new Semaphore(3);
测试代码如下所示,开启10个线程获取数据库连接,因为只有三个许可证,三个许可证被获取后,其他线程需要等待当前的三个线程释放许可证才可以获取许可证,所以三个数据库连接、三个数据库连接被获取:
public class SemaphoreStudy implements Runnable{private static Semaphore semaphore = new Semaphore(3);@Overridepublic void run() {try {semaphore.acquire();System.out.print("获得数据库连接");TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}semaphore.release();}public static void main(String[] args) {for (int i=0; i<10; i++) {;new Thread(new SemaphoreStudy()).start();}}
}
运行截图,三个、三个数据库连接被获取。
使用 tryAcquire() 进行修改, tryAcquire() 尝试获取许可证,没有许可证不阻塞,测试代码如下:
public class SemaphoreStudy implements Runnable{private static Semaphore semaphore = new Semaphore(3);@Overridepublic void run() {try {if (semaphore.tryAcquire()) {System.out.println("获得数据库连接");TimeUnit.MILLISECONDS.sleep(1000);semaphore.release();}} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {for (int i=0; i<10; i++) {;new Thread(new SemaphoreStudy()).start();}}
}
运行截图,7个获取不到许可证的线程,不阻塞等待: