查看源码得知:
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();
}
}