写在前面:
在前面两篇博客中,介绍了CountDownLatch、CyclicBarrier类的使用,这篇博客中,将会总结Semaphore类的使用,完善Java并发包中的3个工具类的使用总结。
Semaphore
Semaphore是用来控制程序中并发访问一个特定资源的线程数量,Semaphore通过协调各个线程,从而保证了资源的调度。
- Semaphore的构造器
我们来看一下JDK8中提供的Semaphore构造器。
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
我们看到,在我们创建实例的时候,要传入一个int类型的参数,这个参数也就是我们可以并发访问的线程数量。
- 应用场景:
Semaphore多用于流量控制,比如是比较重要,特定的资源获取,eg:数据库连接。
下面来看一个数据库连接的demo,demo中,为线程池定义30个连接,但是Semophore只允许有10个线程并发访问数据库连接,并保存数据。我们来看一下代码实现:
package semaphore;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreDemo1 {
private static final int THREAD_COUNT = 30;
private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
private static Semaphore s = new Semaphore(10);
public static void main(String[] args) {
for (int i = 0; i < THREAD_COUNT; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
s.acquire();// 允许并连接
System.out.println("保存数据");
s.release();// 将连接返还给Semaphore
} catch (InterruptedException e) {
}
}
});
}
// 关闭线程池
threadPool.shutdown();
}
}
在控制台中,会输出10个“保存数据”,也就是说,虽然线程池虽然允许有30个线程同时运行,但是由于我们在Semaphore中定义了,只允许10个线程同时并发访问,也就保证了线程的资源访问安全。
- Semaphore提供的方法:
acquire();// 获取一个许可
release();// 返还给Semaphore一个许可
tryAcquire();//尝试获取许可
availablePermits();//返回当前Semophore中可用的许可数量
getQueueLength();//返回正在等待获取许可的线程数量
hasQueuedThreads();//是否有线程正在等待获取许可
reducePermits(int reduction)//通过传入一个reduction参数,来减少Semophore的初始许可数量
Collection<Thread> getQueuedThreads();//返回一个存放所有等待获取连接的线程集合