java多线程-java semaphore(信号量)

sancaiodm Java 2021-09-11 912 0

             在java中,使用了synchronized关键字和Lock锁实现了资源的并发访问控制,在同一时间只允许唯一一个线程进入临界区访问资源(读锁除外),这样子控制的主要目的是为了解决多个线程并发同一资源造成的数据不一致的问题。在另外一种场景下,一个资源有多个副本可供同时使用,比如打印机房有多个打印机、厕所有多个坑可供同时使用,这种情况下,Java提供了另外的并发访问控制--资源的多副本的并发访问控制,

通俗说:一个资源在同时一时间可以允许设定的数目线程并发访问。


如果空闲计数器值为0,则未访问到资源的线程都会进入休眠。当某个线程使用完共享资源后,释放信号量,并将信号量内部的计数器加1,之前进入休眠的线程将被唤醒并再次试图获得信号量。

通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

acquire() // 获取一个许可证,只有获得了许可证,才可以对资源进行操作,对应一个release()
acquire(int n) // 获取N个许可证,对应N个release()
release() // 释放一个许可证
release(int n) // 释放多个许可证
availablePermits() // 返回Semaphore对象中当前可以用的许可数
drainPermits() // 获取并返回所有的许可个数,并且将可用的许可重置为0
getQueueLength() // 取得等待的许可线程个数
hasQueueThreads() // 判断有没有线程在等待这个许可
tryAcquire() // 尝试获取1个许可。如果获取不到则返回false,通常与if语句结合使用,其具有无阻塞的特点。无阻塞的特点可以使不至于在同步处于一直持续等待的状态。
tryAcquire(long timeout,TimeUnit unit) // 在指定的时间内尝试获取1个许可,如果获取不到则返回false


举个简单的例子:

       现有两个村子,在这两村子之间的的路中间必须经过一座桥,而这桥的最大载量是10辆车,如果桥上的车超了10辆就会压垮桥,那怎么办了?只能在桥两端安排各安排一个管理员,每人手里拿5个桥的通行证,要过桥的车必须在管理员这里领取通行证才可以上桥,在另一端下桥时把通行证还给另一个管理员,如此控制桥的通行量,如果管理员手里没有通行证了,那不好意思 你必须在桥边上等着,等有人下桥了还了通行证,你拿到通行证后你才可以上桥,semaphore的作用就与此两管理员的作用是一样,控制管理并发数量,


如下所示 如果使用者申请到信号量后一直持有该信号量,未及时释放信号量,则后面的使用会一直处于堵塞状态无法使用到资源,

image.png


如果需求是判断任务线程处理是否超时,使用semaphore是一个不错的选择,如下图,使用sleep(3000)毫秒虚拟耗时操作,然后用tryAcquire(2000,kkk  如果在规定时间后无法获取许可证,则说明线程当前未释放许可证,业务未处理完成,(注意:在超时判断后 22,33部分仍为继续处理))


image.png



我们再看另一个种情况:如果在初始化时,信号量数量是0,然后去申请许可证,执行结果:始终无法获取许可证,如下图

image.png


如果在初始化信号量时,设置许可证数量为0,但在执行中不申请许可证,结果一切正常,如下图

image.png

评论