Semaphore一个计数信号量。信号量维护了一个许可集合; 通过acquire()和release()来获取和释放访问许可证。只有通过acquire获取了许可证的线程才能执行,否则阻塞。通过release释放许可证其他线程才能进行获取。
公平性:没有办法保证线程能够公平地可从信号量中获得许可。也就是说,无法担保掉第一个调用 acquire()的线程会是第一个获得一个许可的线程。 如果第一个线程在等待一个许可时发生阻塞, 而第二个线程前来索要一个许可的时候刚好有一个许可被释放出来, 那么它就可能会在第一个线程之前获得许可。如果你想要强制公平,Semaphore 类有一个具有一个布尔类型的参数的构造子,通过这个参数以告知 Semaphore 是否要强制公平。强制公平会影响到并发性能,所以除非你确实需要它否则不要启用它。
package com.didispace;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* @author: Kevin
* @官网: www.mimaxueyuan.com
* @Q Q群: 660567408
* @Email: mimaxueyuan@163.com
* [每天进步一点点、人生带来大改变...]
* [本代码对应视频地址:http://study.163.com/course/introduction/1004176043.htm]
*/
public class SemaphoreTest1 {
public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5个线程同时访问(设置许可证的数量),默认是不公平的
//final Semaphore semp = new Semaphore(1);
// 强制公平
final Semaphore semp = new Semaphore(2);
// 模拟多个客户端并发访问
for (int index = 0; index < 5; index++) {
Runnable run = () -> {
try {
System.out.println(Thread.currentThread().getName() + "尝试获取许可证");
// 获取许可
semp.acquire();
System.out.println(Thread.currentThread().getName() + "获取许可证");
Thread.sleep(1000);
// 访问完后,释放 ,如果屏蔽下面的语句,则在控制台只能打印5条记录,之后线程一直阻塞
System.out.println(Thread.currentThread().getName() + "释放许可证");
semp.release();
} catch (InterruptedException e) {
}
};
exec.execute(run);
}
// 退出线程池
exec.shutdown();
}
}