View the source code to know:
LinkedBlockingQueue adopts the technology of lock separation
// remove the lock private final ReentrantLock takeLock = new ReentrantLock(); // remove the lock condition private final Condition notEmpty = takeLock.newCondition(); //insert lock private final ReentrantLock putLock = new ReentrantLock(); //insert lock condition private final Condition notFull = putLock.newCondition();
View the put method source code
public void put(E e) throws InterruptedException { // check that the element is empty if (e == null) throw new NullPointerException(); //set element value int c = -1; //create node Node<E> node = new Node<E>(e); //Acquire insert lock final ReentrantLock putLock = this.putLock; //set the number final AtomicInteger count = this.count; // try to lock putLock.lockInterruptibly(); try { // Judging if this number is equal to the number of containers, the container is full while (count.get() == capacity) { //wait notFull.await(); } //insert enqueue(node); //length+1 //The c obtained here should be the original data, getAndIncrement is equivalent to i++ c = count.getAndIncrement(); / / Determine whether it is less than the container volume after +1 if (c + 1 < capacity) // Less than, notify other insert threads to insert notFull.signal(); } finally { //unlock putLock.unlock(); } //If c==0 means there was no element, now there is an element //So the wait in its queue must be released if (c == 0) signalNotEmpty(); }
Among them, this source code has been understood for a long time: why do you want to add this sentence?
if (c == 0) signalNotEmpty();
Since c acquires the data before adding the element, it is judged to be 0, which means that the queue was empty before, resulting in the thread in the take method being in a waiting state. This method can release the waiting thread in the take method, so that it can Obtain resources, as follows c is the original queue length obtained
//The c obtained here should be the original data, getAndIncrement is equivalent to i++ c = count.getAndIncrement();
signalNotEmpty方法 private void signalNotEmpty() {
// get the lock final ReentrantLock takeLock = this.takeLock;
//Because the notification operation needs to be performed later, the lock must be acquired first takeLock.lock(); try {
//Notify that there are elements in the queue now, you can get the elements notEmpty.signal(); } finally {
//unlock takeLock.unlock(); } }