一个计数信号量。 在概念上,信号量维持一组许可证。 如果有必要,每个acquire()都会阻塞,直到许可证可用,然后才能使用它。 每个release()添加许可证,潜在地释放阻塞的线程。 记得以前校招,一个公司对应很多面试的学生,因为人数太多每次至多面试5个人,其他人只能等待,除非有人出来,等待的人才有机会进去,一般是排队公平进去,但是大家为了找工作都是抢着进去面试,大概是这么个意思。等待就是acquire(),有人出来就是release(),Semaphore底层使用AQS实现
案例分析
public class SemaphoreDemo {
//添加3个许可证,采取公平策略,默认是分公平的
static Semaphore semaphore = new Semaphore(3, true);
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(50);
for (int i = 0; i < 10; i++) {
service.submit(new Task());
}
service.shutdown();
}
static class Task implements Runnable {
@Override
public void run() {
try {
//每个线程需要3个许可证才能进来,如果没有3个就阻塞,直到有满足的许可证可用
semaphore.acquire(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到了许可证");
// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName() + "释放了许可证");
//释放三个许可证
semaphore.release(3);
}
}
}
如果 semaphore.acquire(3);改为 semaphore.acquire(4);那么所有线程都会阻塞,因为总共就只有三个许可证,或者 semaphore.release(3);改为 semaphore.release(2);那么第从二个线程开始所有线程都会阻塞,因为执行需要3个许可证,但是第一个执行的线程只释放了2个许可证
总之.release()操作happen-before acquire()操作,即释放操作在获取操作之前,释放对获取可见
此类共有两个构造方法,两个参数的构造可以选择公平策略,默认是非公平的。
.release()与acquire()默认参数是1