跳到主要内容

Java并发编程学习十:线程协作

一、Semaphore

Semaphore,即信号量,可以用于控制那些需要限制并发访问量的资源。

信号量会维护“许可证”的计数,而线程去访问共享资源前,必须先拿到许可证。线程可以从信号量中去“获取”一个许可证,一旦线程获取之后,信号量持有的许可证就转移过去了,所以信号量手中剩余的许可证要减一。

线程也可以“释放”一个许可证,如果线程释放了许可证,这个许可证相当于被归还给信号量了,于是信号量中的许可证的可用数量加一。

当信号量拥有的许可证数量减到 0 时,如果下个线程还想要获得许可证,那么这个线程就必须等待,直到之前得到许可证的线程释放,它才能获取。

1. 使用流程

Semaphore的使用流程可以分为三步:

  • 初始化信号量,Semaphore的构造函数:public Semaphore(int permits, boolean fair),permits用于指定许可证的数量,fair代表是否公平,传入true代表公平策略,传入false代表非公平策略(允许插队)。
  • 让线程调用 acquire 方法或者 acquireUninterruptibly方法获取许可证,只有这个方法能顺利执行下去的话,线程才能进一步访问后面的调用服务的方法。如果此时信号量已经没有剩余的许可证了,那么线程就会等在 acquire 方法的这一行代码中。
  • 调用 release() 来释放许可证,将许可证还给信号量
2. 方法介绍

a. acquire() & acquireUninterruptibly()

两个方法都是获取许可证的方法,功能相似,但是acquire() 是可以支持中断的,也就是说,它在获取信号量的期间,假设这个线程被中断了,那么它就会跳出 acquire() 方法,不再继续尝试获取了。而 acquireUninterruptibly() 方法是不会被中断的。

b. tryAcquire()

该方法和之前介绍锁的 trylock 思维是一致的,是尝试获取许可证,相当于看看现在有没有空闲的许可证,如果有就获取,如果现在获取不到也没关系,不必陷入阻塞,可以去做别的事。

c. tryAcquire(long timeout, TimeUnit unit)

tryAcquire的重载方法,传入了超时时间。在超时时间内获取到了许可证,则往下继续执行;如果超时时间到,依然获取不到许可证,它就认为获取失败,且返回 false。