-
轮询方式
(1) 基类
@ThreadSafe public abstract class BaseBoundedBuffer<V> { @GuardedBy("this") private final V[] buf; @GuardedBy("this") private int tail; @GuardedBy("this") private int head; @GuardedBy("this") private int count; protected 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; } }
(2) 将前提条件的失败传递给调用者
示例
@ThreadSafe public class GrumpyBoundedBuffer<V> extends BaseBoundedBuffer<V> { public GrumpyBoundedBuffer() { this(100); } public GrumpyBoundedBuffer(int size) { super(size); } public synchronized void put(V v) throws BufferFullException { if (isFull()) { throw new BufferFullException(); } doPut(v); } public synchronized V take() throws BufferEmptyException { if (isEmpty()) { throw new BufferEmptyException(); } return doTake(); } }
这种方式存在的问题:
异常应该用于真正发生异常条件的情况, 而缓存空或者满不属于异常情况.
这加大了调用者的负担(要处理异常); 并且导致有些功能无法实现(例如先到先处理FIFO, 调用者很可能不会保存元素的顺序)
(2) 真正的轮询方式
@ThreadSafe public class SleepyBoundedBuffer<V> extends BaseBoundedBuffer<V> { private int SLEEP_GRANULARITY = 60; public SleepyBoundedBuffer() { this(100); } public SleepyBoundedBuffer(int size) { super(size); } public void put(V v) throws InterruptedException { while (true) { synchronized (this) { if (!isFull()) { doPut(v); return; } } Thread.sleep(SLEEP_GRANULARITY); } } public V take() throws InterruptedException { while (true) { synchronized (this) { if (!isEmpty()) { return doTake(); } } Thread.sleep(SLEEP_GRANULARITY); } } }
优点: 调用者无需catch异常; 提供了取消机制(Thread.sleep()中抛出InterruptedException直接向外抛)
问题: 睡眠时间SLEEP_GRANULARITY变量的值很微妙: 取的小的时候, 响应性好但是很多CPU时钟周期会被浪费(如果这个值是0那么一直被浪费称为__自旋等待__); 取的大的时候CPU使用率高但响应慢
-
条件队列
(1) 使得一组线程能够通过某种方式等待特定的条件为真
(2) Java的每个对象都可以作为内置锁, 每个对象也都可以作为一个条件队列
内置的API是wait, notify, notifyAll
(3) 对象的内置锁与其内部条件队列是相互关联的, 要调用对象X中条件队列的任何一个方法, 必须持有对象X上的锁
(4) Object.wait()会__自动释放锁__, 并请求操作系统__挂起当前线程__, 从而使得其他线程有机会获得这个锁;
当被挂起的线程醒来时, 它将在wait()返回之前__视图重新获取锁__
在重新请求锁时, 被唤醒的线程不具有特殊的优先级, 它将和其他要获取锁的线程一并竞争
(5) 示例
@ThreadSafe public class BoundedBuffer<V> extends BaseBoundedBuffer<V> { // CONDITION PREDICATE: not-full (!isFull()) // CONDITION PREDICATE: not-empty (!isEmpty()) public BoundedBuffer() { this(100); } public BoundedBuffer(int size) { super(size); } // BLOCKS-UNTIL: not-full public synchronized void put(V v) throws InterruptedException { while (isFull()) { this.wait(); } doPut(v); this.notifyAll(); } // BLOCKS-UNTIL: not-empty public synchronized V take() throws InterruptedException { while (isEmpty()) { this.wait(); } V v = doTake(); this.notifyAll(); return v; } }
chapter14_构建自定义的同步工具_1_状态依赖性的管理
最新推荐文章于 2023-10-20 19:12:27 发布