LinkedBlockingQueue JUC LinkedBlockingQueue JUC LinkedBlockingQueue JUC LinkedBlockingQueue

LinkedBlockingQueue has the following features:

  • LinkedBlockingQueue is a blocking queue, and the underlying single list implementation is ~
  • The element enters the queue from the end and exits the queue from the head, in accordance with FIFO~
  • All operations of the Collection and Iterator interfaces can be used because they implement ~
  • LinkedBlockingQueue Read and write operations are locked, but the read and write operations use two different locks, so the read and write operations can be performed at the same time

LinkedBlockingQueue extends AbstractQueue and implements the BlockingQueue interface.

// Insert the specified element at the end of the queue (if available immediately and does not exceed the capacity of the queue)
// Returns true on success and throws IllegalStateException if the queue is full.
boolean add(E e); 

// Insert the specified element at the end of the queue (if available immediately and does not exceed the capacity of the queue)
// Insert the specified element at the end of the queue. If the queue is full,
// Wait for the available space until the specified wait time is reached
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException; 

// Inserts the specified element at the end of the queue, and if the queue is full, waits (blocking).
void put(E e) throws InterruptedException; 

// Get and move the head of the queue, wait (block) if there are no elements,
// Until an element wakes up the waiting thread to perform the operation
E take(a) throws InterruptedException; 

// Gets and removes the head of this queue, or returns NULL if the queue is empty.
E poll(a);
// Get and move the head of the queue, wait until the element is fetched before the specified wait time, and the method ends after the specified wait time
E poll(long timeout, TimeUnit unit) throws InterruptedException; 

Removes a single instance of the specified element (if present) from this queue.
boolean remove(Object o); 

NoSuchElementException = NoSuchElementException = NoSuchElementException
E element(a); 

// Get, but do not remove, the head of this queue; If this queue is empty, null is returned.
E peek(a); 
Copy the code

LinkedBlockingQueue there are many read and write methods, but the most commonly used are put() and take(), because they block, so we will talk about the implementation of the two methods in LinkedBlockingQueue from the source perspective.

Put (); put();

public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    // Set c to -1, indicating failure
    int c = -1;
    Node<E> node = new Node<E>(e);
    // Get the write lock
    final ReentrantLock putLock = this.putLock;
    // Get the current queue size
    final AtomicInteger count = this.count;
    // Set interruptible locks
    putLock.lockInterruptibly();
    try {
        // The queue is full
        // The current thread is blocked, waiting for another thread to wake up.
        while (count.get() == capacity) {
            // Wait indefinitely
            notFull.await();
        }
        // Add to queue end
        enqueue(node);
        // Get the current queue number
        c = count.getAndIncrement();
        // If the queue is full, try to wake up a put waiting thread
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        / / releases the lock
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();
}
Copy the code

The source code for the put() method is not hard to read. It is very easy to read. The process of putting () method is as follows:

  • 1, first lock, to ensure the concurrent security of containers ~
  • 2. Add new data to queue and append the data to queue tail ~
  • If the queue is full, the current thread is blocked, waiting to be woken up
  • If the queue is not empty, it will call up the queue waiting thread of put (when the queue is not empty) or the queue waiting thread of take (when the queue is not empty). This ensures that once the queue meets the put or take condition, it will immediately call up the blocking thread and continue to run. There are two types of offer, one that returns false directly, and the other that returns false~ after a certain amount of time
  • 5, release lock ~

Other new methods, such as offer, can view the source code, and are not much different from put()

Take ();

public E take(a) throws InterruptedException {
    E x;
    // Default negative number
    int c = -1;
    // The number of current linked lists
    final AtomicInteger count = this.count;
    // Get read lock
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly();
    try {
        // When the queue is empty, it blocks, waiting for another thread to wake up
        while (count.get() == 0) {
            notEmpty.await();
        }
        // Take an element from the head of the queue
        x = dequeue();
        // Subtract one, C is larger than the actual queue data
        c = count.getAndDecrement();
        // if c is greater than 0, the queue has a value to wake up the previously blocked reader thread
        if (c > 1)
            notEmpty.signal();
    } finally {
        / / releases the lock
        takeLock.unlock();
    }
    // If the queue is not full, the PUT waiting thread ~ can be woken up
    if (c == capacity)
        signalNotFull();
    return x;
}
Copy the code

The take() method is similar to the put() method and is the opposite operation, so I won’t go into too much detail

That’s all I have to say about LinkedBlockingQueue. Thank you for reading

Welcome to pay attention to the public number [Internet flathead brother], grow up together, progress together ~.