今天我们分析一下LinkedBlockingQueue,这是一个我们使用频率比较高的类。
public static void main(String[] args) throws Exception {//我们这个LinkedBlockingQueue源码分三个关键步骤//步骤一:先看一个其构造函数,以及核心的属性 LinkedBlockingQueuequeue = new LinkedBlockingQueue (); //步骤二:看一下其关键步骤,插入数据的步骤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 (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 node = new Node (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;}
如果有了之前的基础,阅读这段代码应该是比较简单的。
搞定,手工!