依赖状态的线程任务的等待方式之忙等待 2019-04-13

引入:

  有时候我们执行一个操作,需要一个前提条件,只有在条件满足的情况下,才能继续执行。在单线程程序中,如果某个状态变量不满足条件,则基本上可以直接返回。但是,在并发程序中,基于状态的条件可能会由于其他线程的操作而改变。而且存在这种需要,即某个操作一定要完成,如果当前条件不满足,没关系,我可以等,等到条件满足的时候再执行。今天,我们就来聊一聊等待的几种方式。

忙等待 / 自旋等待。让权等待 / 轮询与休眠条件队列

 

情景条件

  我们要实现一个有界缓存,其中用不同的等待方式处理前提条件失败的问题。在每种实现中都扩展了BaseBoundedBuffer,这个类中实现了一个基于数组的循环缓存,其中各个缓存状态变量(buf、head、tail和count)均由缓存的内置锁来保护。它还提供了同步的doPut和doTake方法,并在子类中通过这些方法来实现put和take操作,底层的状态将对子类隐藏。

此段代码来自《Java Concurrency in Practice》

public abstract class BaseBoundedBuffer<V> { private final V[] buf //缓冲数组 private int tail //缓冲数据尾部索引 private int head //头部索引 private int count //存储的数据量 public BaseBoundedBuffer(int capacity) { this.buf = (V[]) new Object[capacity] } protected synchronized final void doPut(V v) { buf[tail] = v if (++tail == buf.length) tail = 0 ++count } protected synchronized final V doTake() { V v = buf[head] buf[head] = null if (++head == buf.length) head = 0 --count return v } public synchronized final boolean isFull() { return count == buf.length } public synchronized final boolean isEmpty() { return count == 0 }}

忙等待:反复检查条件是否为真,直到条件达到,继而完成后续任务。

我们来看看,忙等待的实现方式:

public class BusyWaitBoundedBuffer<V> extends BaseBoundedBuffer<V> { public BusyWaitBoundedBuffer(int size) { super(size) } public void put(V v) throws InterruptedException { while(true) { synchronized (this) { if(!isFull()) { doPut(v) return } } } } public V take() throws InterruptedException { while(true) { synchronized (this) { if(!isEmpty()) return doTake() } } }}

这里的两个方法在访问缓存时都采用"先检查,再运行"的逻辑策略,非线程安全,因为条件可能在"检查之后,运行之前"的中间时刻,被其他线程修改,以至于,在运行的时候,前提条件已经不满足了,故需要对put和take两个方法都进行同步,共用同一个锁以确保实现对缓冲状态的独占访问,即某一时刻只能有一个线程可以访问操作缓冲数组。也就是说,在put方法执行的一次尝试中,take方法不能被调用,不能改变缓冲数组状态。

还有一点,值得注意的是,while循环并不在同步块内,而是同步块在while循环内,也就是每执行一次条件检查,如果不满足,需要释放掉锁。不然另一个方法就拿不到锁,也就不能改变状态,条件就永远不能发生改变,这个方法就变成了死等待

这样做,虽然在逻辑上实现了功能要求,但是在性能上却可能消耗过多的CPU时间,因为它占据着CPU,不做计算,而只是等待。

“尚未解决的疑惑”:线程等待锁的时候是否会被JVM挂起,调出CPU?如果是这样的话,那么上下文切换的开销也会很大,因为每检查一次条件,需要进出CPU两次。

 

Copyright © 2019 齐发app下载 All Rights Reserved
施秀薇
地址:辽宁省丹东东港市前阳镇榆树村
全国统一热线:15267163894