在JUC包下,有一个Semaphore类,翻译成信号量,Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。Semaphore跟锁(synchronized、Lock)有点相似,不同的地方是,锁同一时刻只允许一个线程访问某一资源,而Semaphore则可以控制同一时刻多个线程访问某一资源。
Semaphore(信号量)并不是Java语言特有的,几乎所有的并发语言都有。所以也就存在一个信号量模型的概念,如下图所示:
信号量模型比较简单,可以概括为:一个计数器、一个队列、三个方法。
计数器:记录当前还可以运行多少个资源访问资源。
队列:待访问资源的线程
三个方法:
init():初始化计数器的值,可就是允许多少线程同时访问资源。up():计数器加1,有线程归还资源时,如果计数器的值大于或者等于0时,从等待队列中唤醒一个线程down():计数器减1,有线程占用资源时,如果此时计数器的值小于0,线程将被阻塞。这三个方法都是原子性的,由实现方保证原子性。例如在Java语言中,JUC包下的Semaphore实现了信号量模型,所以Semaphore保证了这三个方法的原子性。
Semaphore是基于AbstractQueuedSynchronizer接口实现信号量模型的。AbstractQueuedSynchronizer提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架,利用了一个int来表示状态,通过类似acquire和release的方式来操纵状态。
在Semaphore类中,实现了两种信号量:公平的信号量和非公平的信号量,公平的信号量就是大家排好队,先到先进,非公平的信号量就是不一定先到先进,允许插队。非公平的信号量效率会高一些,所以默认使用的是非公平信号量。具体的可以查看Semaphore类实现源码。
Semaphore类中,主要有以下方法:
Semaphore类的实现就了解得差不多了。可能你会有疑问Semaphore的应用场景是什么?Semaphore可以用来限流(流量控制),在一些公共资源有限的场景下,Semaphore可以派上用场。比如在做日志清洗时,可能有几十个线程在并发清洗,但是将清洗的数据存入到数据库时,可能只给数据库分配了10个连接池,这样两边的线程数就不对等了,我们必须保证同时只能有10个线程获取数据库链接,否则就会存在大量线程无法连接上数据库。
用Semaphore信号量来模拟这操作,代码如下:
运行效果如下:
从结果中,可以看出,每秒只有5个线程在执行,这符合我们的预期。
好了,关于Semaphore的内容就结束了,更加详细的还请您查阅相关资料和阅读Semaphore源码。希望这篇文章对您的学习或者工作有所帮助。
感谢您的阅读,祝好。
最后
目前互联网上很多大佬都有Semaphore(信号量)相关文章,如有雷同,请多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有所错误之处,还望提出,谢谢。