《Java并发编程实战》第十四章 构建自己定义的同步工具 读书笔记


一、状态依赖性的管理

有界缓存实现的基类
@ ThreadSafe
public abstract class BaseBoundedBuffer<E> {
       @GuardeBy( "this" ) private final E[] buf;
       @GuardeBy( "this" ) private int tail;
       @GuardeBy( "this" ) private int head;
       @GuardeBy( "this" ) private int count;

       protected BaseBoundedBuffer( int capacity) {
             this .buf = (E[]) new Object[capacity];
      }

       protected synchronized final void doPut(E E) {
            buf[tail] = E;
             if (++tail == buf.length) {
                  tail = 0;
            }
            ++count;
      }

       protected synchronized final E doTake() {
            E E = buf[head];
            buf[head] = null ;
             if (++head == buf.length) {
                  head = 0;
            }
            --count;
             return E;
      }

       public synchronized final boolean isFull() {
             return count == buf.length;
      }

       public synchronized final boolean isEmpty() {
             return count == 0;
      }
}


1 演示样例:将前提条件的失败传递给调用者
@ ThreadSafe
public class GrumpyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
       public GrumpyBoundedBuffer( int size){
             super (size);
      }
      
       public synchronized void put(V v){
             if (isFull()){
                   throw new BufferFullException ();
            }
            doPut(v);
      }
      
       public synchronized V take(){
             if (isEmpty())
                   throw new BufferEmptyExeption ();
             return doTake();
      }
}

缓存为空或者已满都不是异常情况,使用者必需要捕获这些异常才干进行正确的处理。
       while (true ){
             try {
                  V item = buffer.take();
                   // 对于item运行一些操作
                   break ;
            } catch (BufferEmptyException e) {
                  Thread. sleep(SLEEP_GRANULARITY );
            }
      }


2 演示样例:通过轮询与休眠来实现简单的堵塞
从上面的代码能够看出。堵塞与出现异常都须要方法的使用者来处理,如今尝试都封装到有界缓存中。

@ ThreadSafe
public class SleepyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
       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);
            }
      }
}

3 条件队列
不须要使用while(true),改为使用wait、notifyAll
@ ThreadSafe
public class BoundedBuffer<V> extends BaseBoundedBuffer<V> {

       // 条件谓词:not-full (!isFull())
       // 条件谓词:not-empty (!isEmpty())
      
       public BoundedBuffer( int size) {
             super (size);
      }
      
       // 堵塞并直道:not-full
       public synchronized void put(V v) throws InterruptedException{
             while (isFull()){
                  wait();
            }
            doPut(v);
            notifyAll();
      }
      
       // 堵塞并直道:not-empty
       public synchronized V take() throws InterruptedException{
             while (isEmpty()){
                  wait();
            }
            V v = doTake();
            notifyAll();
             return v;
      }
}

二、使用条件队列

1 条件谓词
要想正确地使用条件队列,关键是找出对象在哪个条件谓词上等待。

2 过早唤醒
比如:内置条件队列中有多个条件谓语。此时假设调用notifyAll其含义是通知全部wait,可是并不一定全部条件谓语都满足运行条件。


当使用条件等待时(比如Object.wait或Condition.await):
. 通常都有一个条件谓词--包含一些对象状态的測试,线程在运行前必须首先通过这些測试。


. 在调用wait之前測试条件谓词,而且从wait中返回时再次进行測试。
. 在一个循环中调用wait。
. 确保使用与条件队列相关的锁来保护构成条件谓词的各个状态变量。
. 当调用wait、notify或notifyAll等方法时。一定要持有与条件队列相关的锁。
. 在检查条件谓词之后以及開始运行对应的操作之前。不要释放锁。


3 丢失的信号
已经满足通知的条件发出通知,可是之后才进入堵塞wait状态。所以wait永远等不到在其前面发出的notify。

4 通知
5 演示样例:阀门类
6 子类的安全问题
7 封装条件队列
8 入口协议与出口协议


三、显式的Condition对象
四、Synchronizer剖析
五、AbstractQueuedSynchronizer
六、java.util.concurrent同步器类中的 AQS
1 ReentrantLock
2 Semaphore与CountDownLatch
3 FutureTask
4 ReentrantReadWriteLock
原文地址:https://www.cnblogs.com/mfrbuaa/p/5171998.html