以上代码的执行结果如下:
从上述的结果我们可以看出,当有 5 辆车同时需要进入停车场时,因为停车场的停车位只有 2 个,所以停车场最多只能容纳 2 辆车。此时我们通过 Semaphore 的 acquire 方法(阻塞等待)和 release 方法(颁发一个证书)顺利的实现了限流的功能,让停车场的车辆数始终控制在 2 辆车以下(等于或小于 2 辆车)。 个人评价
我(Semaphore)实现证书控制手段有两种,一种公平模式和非公平模式,当然为了执行的性能考虑,默认情况下我采取的是非公平的方式,具体实现可见源码:
public Semaphore(int permits) { sync = new NonfairSync(permits); // 非公平模式 } 关于公平模式和非公平模式所谓的公平模式就是以调用 acquire() 的先后顺序来决定获取许可证的顺序的,公平模式遵循先进先出(FIFO)原则;而非公平模式是抢占式的,也就是有可能一个新的获取线程恰好在一个许可证释放时得到了这个许可证,而前面还有等待的线程。
显然使用非公平的模式性能更高,因为它会把许可证发放给刚好准备好的线程,而不用再根据先后顺序去“叫号”了。
使用公平模式当然,你可以手动选择使用公平模式来运行 Semaphore,Semaphore 提供了两个构造函数,源码如下:
public Semaphore(int permits) { sync = new NonfairSync(permits); } public Semaphore(int permits, boolean fair) { sync = fair ? new FairSync(permits) : new NonfairSync(permits); }如果想用公平模式就可以使用第二个构造函数 Semaphore(int permits, boolean fair),将 fair 值设置为 true 就是公平模式来获取证书了。
其他补充我还提供了一些其他方法,用于实现更多的功能,详情如下:
int availablePermits():返回此信号量中当前可用的许可证数。
int getQueueLength():返回正在等待获取许可证的线程数。
boolean hasQueuedThreads():是否有线程正在等待获取许可证。
boolean isFair():查询 Semaphore 使用的是公平模式还是非公平模式,如果此信号量使用的是公平模式则返回 true。
void release(int permits):释放给定数量的许可证,将其返回到信号量。
tryAcquire():从这个信号量获得许可证,只有在调用时可以使用该许可证。
tryAcquire(int permits):从这个信号量获取给定数量的许可证,只有在调用时全部可用。
tryAcquire(int permits, long timeout, TimeUnit unit):从该信号量获取给定数量的许可证,如果在给定的等待时间内全部可用,并且当前线程尚未 interrupted。
tryAcquire(long timeout, TimeUnit unit):如果在给定的等待时间内可用,并且当前线程尚未 到达 interrupted,则从该信号量获取许可。
void reducePermits(int reduction) :减少可用的许可证数量 reduction 个,它是 protected 方法。
Collection getQueuedThreads() :返回所有等待获取许可证的线程集合,它是 protected 方法。
总结Semaphore 信号量是用来管理一组证书的,默认情况下它采取的是非公平的方式来管理证书,这样做的目的是为了实现高性能。Semaphore 中包含了两个重要的方法:release() 方法发布一个许可证书;acquire() 方法阻塞并等待一个证书。当线程调用了 acquire() 方法只有拥有了证书才能继续执行,因此可以使用 Semaphore 来实现限流。