Semaphore 信号量模型:一个计数器,一个等待队列,三个方法
信号量模型init():设置计数器的初始值。
down():计数器的值减 1;如果此时计数器的值小于 0,则当前线程将被阻塞,否则当前线程可以继续执行。
up():计数器的值加 1;如果此时计数器的值小于或者等于 0,则唤醒等待队列中的一个线程,并将其从等待队列中移除。
这里必须要解释一下up()方法中计数器的值小于或者等于 0的设定。需要资源的线程(无论是正在运行的,还是等待的)数量 = 计数器初始值 - 计数器当前值。 举个例子,计数器初始化为2,两个线程进入临界区,此时计数器数值为0,很显然, 2=2-0;再来一个线程,down()后计数器为-1,这个新来的线程阻塞,此时 3 = 2 - (-1)。 那么接着解释为什么是小于或等于0. 反证, 如果计时器大于0, 根据上面计算公式 需要资源的线程 = 初始值 - 当前值, 需要资源的线程数必定小于初始值,也就是说,资源完全够用,根本没有线程阻塞,那还唤醒个锤子? 必须是当前值小于等于0才去唤醒
init()、down() 和 up() 三个方法都是原子性的,而在Java SDK包中, down()和up()分别对应acquire()和release(),意思也很贴切。
java中使用信号量的例子信号量可以实现的独特功能就是同时允许多个线程进入临界区,但是信号量不能做的就是同时唤醒多个线程去争抢锁,只能唤醒一个阻塞中的线程,而且信号量模型是没有Condition的概念的,即阻塞线程被醒了直接就运行了而不会去检查此时临界条件是否已经不满足了,基于此考虑信号量模型才会设计出只能让一个线程被唤醒,否则就会出现因为缺少Condition检查而带来的线程安全问题。正因为缺失了Condition,所以用信号量来实现阻塞队列就很麻烦,因为要自己实现类似Condition的逻辑。
本节问题:在上面对象池的例子中,对象保存在了 Vector 中,Vector 是 Java 提供的线程安全的容器,如果我们把 Vector 换成 ArrayList,是否可以呢? 补充:例子中的对象池,允许多个线程同时访问,Semaphore初始化为 大于1的数。
回答:不可以。信号量允许多个线程访问资源,尤其是demo中有list的remove和add操作,这都是先定位再操作的方法,如果不是线程安全的,可能会remove一个不存在的数字而出错。add同理。
网友评论