并发容器分析(五)--ConcurrentHashMap

来源:互联网 发布:录音整理软件 编辑:程序博客网 时间:2024/06/15 02:15

一、简介

    BlockingQueue接口定义了一种阻塞的FIFO queue,每一个BlockingQueue都有一个容量,让容量满时往BlockingQueue中添加数据时会造成阻塞,当容量为空时取元素操作会阻塞。ArrayBlockingQueue是对BlockingQueue的一个数组实现,它使用一把全局的锁并行对queue的读写操作,同时使用两个Condition阻塞容量为空时的取操作和容量满时的写操作。

二、具体实现

    ArrayBlockingQueue底层定义如下:

 

Java代码  收藏代码
  1. public class ArrayBlockingQueue<E> extends AbstractQueue<E>  
  2.         implements BlockingQueue<E>, java.io.Serializable {  
  3.   
  4.     // 使用循环数组来实现queue,初始时takeIndex和putIndex均为0  
  5.     private final E[] items;  
  6.     private transient int takeIndex;  
  7.     private transient int putIndex;  
  8.     private int count;  
  9.   
  10.     // 用于并发的锁和条件  
  11.    private final ReentrantLock lock;  
  12.     private final Condition notEmpty;  
  13.     private final Condition notFull;  
  14.   
  15.     /** 
  16.      * 循环数组 
  17.      * Circularly increment i. 
  18.      */  
  19.     final int inc(int i) {  
  20.         return (++i == items.length)? 0 : i;  
  21.     }  
  22.   
  23.     public ArrayBlockingQueue(int capacity, boolean fair) {  
  24.         if (capacity <= 0)  
  25.             throw new IllegalArgumentException();  
  26.         this.items = (E[]) new Object[capacity];  
  27.         // 分配锁及该锁上的condition  
  28.         lock = new ReentrantLock(fair);  
  29.         notEmpty = lock.newCondition();  
  30.         notFull =  lock.newCondition();  
  31.     }  
  32.   
  33.   ...  
  34. }  

   ArrayBlockingQueue的取操作:

Java代码  收藏代码
  1. public class ArrayBlockingQueue<E> extends AbstractQueue<E>  
  2.         implements BlockingQueue<E>, java.io.Serializable {  
  3.   
  4.     private E extract() {  
  5.         final E[] items = this.items;  
  6.         E x = items[takeIndex];  
  7.         items[takeIndex] = null;  
  8.         takeIndex = inc(takeIndex);  
  9.         --count;  
  10.        // 激发notFull条件  
  11.         notFull.signal();  
  12.         return x;  
  13.     }  
  14.   
  15.      /** 
  16.         * condition的await的语义如下: 
  17.      * 与condition相关的锁以原子方式释放,并禁用该线程 
  18.      * 方法返回时,线程必须获得与该condition相关的锁 
  19.      */  
  20.     public E take() throws InterruptedException {  
  21.         final ReentrantLock lock = this.lock;  
  22.         lock.lockInterruptibly();  
  23.         try {  
  24.             try {  
  25.                   // 等待notEmpty的条件  
  26.                 while (count == 0)  
  27.                     notEmpty.await();  
  28.             } catch (InterruptedException ie) {  
  29.                 notEmpty.signal(); // propagate to non-interrupted thread  
  30.                 throw ie;  
  31.             }  
  32.             E x = extract();  
  33.             return x;  
  34.         } finally {  
  35.             lock.unlock();  
  36.         }  
  37.     }  
  38.   
  39.   ...  
  40. }  

   ArrayBlockingQueue的写操作:

Java代码  收藏代码
  1. public class ArrayBlockingQueue<E> extends AbstractQueue<E>  
  2.         implements BlockingQueue<E>, java.io.Serializable {  
  3.   
  4.     private void insert(E x) {  
  5.         items[putIndex] = x;  
  6.         putIndex = inc(putIndex);  
  7.         ++count;  
  8.         notEmpty.signal();  
  9.     }  
  10.   
  11.     public void put(E o) throws InterruptedException {  
  12.         if (o == nullthrow new NullPointerException();  
  13.         final E[] items = this.items;  
  14.         final ReentrantLock lock = this.lock;  
  15.         lock.lockInterruptibly();  
  16.         try {  
  17.             try {  
  18.                   // 等待notFull条件  
  19.            while (count == items.length)  
  20.                     notFull.await();  
  21.             } catch (InterruptedException ie) {  
  22.                 notFull.signal(); // propagate to non-interrupted thread  
  23.                 throw ie;  
  24.             }  
  25.             insert(o);  
  26.         } finally {  
  27.             lock.unlock();  
  28.         }  
  29.     }  
  30.   
  31.   ...  
  32. }  

    注意:ArrayBlockingQueue在读写操作上都需要锁住整个容器,因此吞吐量与一般的实现是相似的,适合于实现“生产者消费者”模式。

http://zhuhui-zj.iteye.com/blog/784192