今天咱们分析一下LinkedBlockingQueue,这是一个咱们使用频率比较高的类。java
public static void main(String[] args) throws Exception { //咱们这个LinkedBlockingQueue源码分三个关键步骤 //步骤一:先看一个其构造函数,以及核心的属性 LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(); //步骤二:看一下其关键步骤,插入数据的步骤 queue.put("张三"); //步骤三:看一下其关键步骤,获取数据的步骤 queue.take(); } 步骤一: public LinkedBlockingQueue() { //设置队列的大小 //其实可见,默认状况下是一个无界队列(相似于无界) this(Integer.MAX_VALUE); } public LinkedBlockingQueue(int capacity) { if (capacity <= 0) throw new IllegalArgumentException(); //设置队列大小 this.capacity = capacity; //初始化一个空节点 last = head = new Node<E>(null); } //获取数据的时候的一把锁 //由于是队列,这把锁在队尾 private final ReentrantLock takeLock = new ReentrantLock(); //关于takeLock的对象 private final Condition notEmpty = takeLock.newCondition(); //put数据的时候的一把锁 //由于是队列,因此这把锁在队头 private final ReentrantLock putLock = new ReentrantLock(); //关于putLock的对象 private final Condition notFull = putLock.newCondition(); 其实LinkedBlockingQueue的设计也是很巧妙的,使用了两把锁去控制。两把锁之间互相不影响。大幅提高了并发的性能。 接下来自咱们分析一下步骤二: public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); // Note: convention in all put/take/etc is to preset local var // holding count negative to indicate failure unless set. int c = -1; //根据当前传入的元素封装节点 Node<E> node = new Node<E>(e); //获取putLocak锁 final ReentrantLock putLock = this.putLock; //统计当前元数据个数 final AtomicInteger count = this.count; //加锁 putLock.lockInterruptibly(); try { //若是队列存满了,那就等待 while (count.get() == capacity) { notFull.await(); } //入队,这个操做其实也很简单 // last = last.next = node; enqueue(node); //入队完了之后递增当前 元素个数 //不过咱们须要知道的是,好比当前的元素个数 //已是9递增到10了。 //这个时候count=10 c=9 c = count.getAndIncrement(); //若是c+1小于总的容量,说明队列至少有一个空间是能够存数据的。 if (c + 1 < capacity) //唤醒以前由于队列满了而处于等待的锁。 notFull.signal(); } finally { //释放锁 putLock.unlock(); } //若是c==0,说明当前的队列里面确定还有元素,能够获取 if (c == 0) //唤醒以前由于队列为空而处于等待的锁 signalNotEmpty(); } 咱们发现其实LinkedBlockingQueue的源码阅读下来难度不大。 public E take() throws InterruptedException { E x; int c = -1; //获取当前元素个数 final AtomicInteger count = this.count; //获取takeLock锁 final ReentrantLock takeLock = this.takeLock; //获取元素的时候加锁 takeLock.lockInterruptibly(); try { //若是当前元素等于0,说明没有元素了 while (count.get() == 0) { //若是队列为空,那么就等待 notEmpty.await(); } //出队,获取元素 //出队的代码也是极其简单就是变化一下指针就能够。 x = dequeue(); //递减元素 //加入当前count 由10 变成了9 //count =10 count=9 c = count.getAndDecrement(); //说明队列不为空 if (c > 1) //不为空,那么就唤醒 可能由于队列为空而处于等待的锁 notEmpty.signal(); } finally { //释放锁 takeLock.unlock(); } //若是c==capacity说明队列里面确定会有不满的元素 if (c == capacity) //唤醒,由于队列满了而处于等待的锁。 signalNotFull(); //返回当前元素 return x; }
若是有了以前的基础,阅读这段代码应该是比较简单的。node
搞定,手工!并发