java 使用semaphore控制并发访问多个资源

是什么?为什么?怎么做?

 

一、是什么

1.semaphore可以保护多个资源

上篇文章中,我们使用semaphore模拟了打印机工作时的情景。

当时semaphore只能用来保护单独一个共享资源:

在这里,semaphore保护了print方法中的代码片段,这个代码片段每次只能被一个线程执行。上一篇文章讲述的是使用semaphore控制并发访问资源。

实际上,semaphore也可以用来保护多个资源的副本,让一个代码片段每次可以被多个线程执行。这一篇文章讲述的是使用semaphore控制多个并发访问资源。

2.和lock的不同

其实没有什么可比性。如果使用lock,每次只有一条线程可以获得锁,保证了数据的安全。如果使用semaphore,决定了某个资源能被多少线程同时访问,保证的是访问资源的线程数量(当然如果semaphore为1,那么实现效果就和互斥锁一样了)。这两个东西作用不一样。

所以,我们一般使用lock来保证线程安全,使用semaphore来限制访问资源的线程数量。

二、为什么

上篇文章只有一台打印机,只需要使用semaphore实现简单的互斥锁功能,所以功能单一,实现起来简单明确。

假如有这样一个情景:现在有一个任务队列,需要在三台不同的打印机上不停打印。如何实现?

对象多了,整个实现思路就需要变化。

三、怎么做

实现思路大致如下:

因为现在不止一台打印机了,所以我们要加入打印队列的概念,有打印任务就交给打印队列去处理,不再具体到哪一台打印机。

首先新建一个打印队列:

因为有三台不同的打印机,所以(最多)可以同时执行三条打印线程,所以信号量为3:

打印队列是干什么的?是分配打印机进行打印的,所以打印队列实际上控制了打印的行为。为了简单,不调用打印机类的打印方法了,直接在打印队列中实现:

打印队列每次使用打印方法,都要去获取空闲的打印机。所以写一个方法进行获取(这里默认是从一号位开始寻找):

最后在main方法中,模拟20条打印请求:

运行结果:

四、总结

我的个人理解:如果只允许一定数量线程同时使用同一资源(比方说同时使用某个方法,执行某个代码块),就应该使用semaphore。

正如上文所说:semaphore可以用来保护多个资源,也就是说一个代码片段每次可以被多个线程执行。我们一般使用lock来保证线程安全,使用semaphore来限制访问资源的线程数量。

发表评论

电子邮件地址不会被公开。 必填项已用*标注