查看源码得知:
LinkedBlockingQueue采用是锁分离的技术
//取出锁 private final ReentrantLock takeLock = new ReentrantLock(); //取出锁条件 private final Condition notEmpty = takeLock.newCondition(); //插入锁 private final ReentrantLock putLock = new ReentrantLock(); //插入锁条件 private final Condition notFull = putLock.newCondition();
查看put方法源码
public void put(E e) throws InterruptedException { //判断元素为空 if (e == null) throw new NullPointerException(); //设置元素值 int c = -1; //创建节点 Node<E> node = new Node<E>(e); //获取插入锁 final ReentrantLock putLock = this.putLock; //设置数量 final AtomicInteger count = this.count; //尝试加锁 putLock.lockInterruptibly(); try { //判断如果这个数量等于容器数量说明容器满了 while (count.get() == capacity) { //等待 notFull.await(); } //插入 enqueue(node); //长度+1 //这里获取的c应该是原本的数据,getAndIncrement相当于i++ c = count.getAndIncrement(); //判断其+1后是否小于容器体积 if (c + 1 < capacity) //小于则通知其他插入线程进行插入 notFull.signal(); } finally { //解锁 putLock.unlock(); } //如果c==0表示本来没有元素,现在已经有元素了 //所以必须将其queue中的等待释放 if (c == 0) signalNotEmpty(); }
其中这句源码理解挺久的:为何要加入这句话呢?
if (c == 0) signalNotEmpty();
由于c为获取的是添加元素前的数据,判断为0说明之前该队列为空,导致take方法中的线程处于等待的状态,通过该方法可以使得其take方法中的等待线程释放,让其可以获取资源,如下c为获取的为原本queue长度
//这里获取的c应该是原本的数据,getAndIncrement相当于i++ c = count.getAndIncrement();
signalNotEmpty方法
private void signalNotEmpty() { //获取取出锁 final ReentrantLock takeLock = this.takeLock; //由于后面需要进行通知操作,所以得先获取锁 takeLock.lock(); try { //通知现在queue里面有元素了,大家可以来获取元素了 notEmpty.signal(); } finally { //解锁 takeLock.unlock(); } }