chapter14_构建自定义的同步工具_1_状态依赖性的管理

时间:2019-03-19
本文章向大家介绍chapter14_构建自定义的同步工具_1_状态依赖性的管理,主要包括chapter14_构建自定义的同步工具_1_状态依赖性的管理使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
  • 轮询方式

    (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;
          }
      }