一个计数信号量。从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每一个acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。
Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。
例如,下面的类使用信号量控制对内容池的访问:这里是一个实际的情况,大家排队上厕所,厕所只有两个位置,来了10个人需要排队。
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class TestSemaphore extends Thread { Semaphore position; private int id; public TestSemaphore(int i, Semaphore s) { this.id = i; this.position = s; } public void run() { try { if (position.availablePermits() > 0) { System.out.println("顾客[" + this.id + "]进入厕所,有空位"); } else { System.out.println("顾客[" + this.id + "]进入厕所,没空位,排队"); } position.acquire(); System.out.println("顾客[" + this.id + "]获得坑位"); Thread.sleep((int) (Math.random() * 1000)); System.out.println("顾客[" + this.id + "]使用完毕"); position.release(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String args[]) { ExecutorService list = Executors.newCachedThreadPool(); Semaphore position = new Semaphore(2); for (int i = 0; i < 10; i++) { list.submit(new TestSemaphore(i + 1, position)); } list.shutdown(); position.acquireUninterruptibly(2); System.out.println("使用完毕,需要清扫了"); position.release(2); } }
Semaphore vs. CountDownLatch
相同点 :
两者都是用于线程同步的工具类,都通过定义了一个继承AbstractQueuedSynchronizer的内部类Sync来实现具体的功能.
不同点 :
1. Semaphore提供了公平和非公平两种策略, 而CountDownLatch则不具备.
2. CountDownLatch: 一个或者是一部分线程,等待另外一部线程都完成操作。
Semaphorr: 维护一个许可集.通常用于限制可以访问某些资源(物理或逻辑的)的线程数目.
3. CountDownLatch中计数是不能被重置的。CountDownLatch适用于一次同步。当使用CountDownLatch时,任何线程允许多次调用countDown(). 那些调用了await()方法的线程将被阻塞,直到那些没有被阻塞线程调用countDown()使计数到达0为止
。
Semaphore允许线程获取许可, 未获得许可的线程需要等待.这样防止了在同一时间有太多的线程执行.Semaphore的值被获取到后是可以释放的,并不像CountDownLatch那样一直减到0。
4. 使用CountDownLatch时,它关注的一个线程或者多个线程需要在其它在一组线程完成操作之后,在去做一些事情。比如:服务的启动等。使用Semaphore时,它关注的是某一个资源最多同时能被几个线程访问.