天天看點

【Java】之 LinkedBlockingQueue 淺析

文章目錄

  • ​​一、簡介​​
  • ​​二、源碼分析​​
  • ​​(1)`put(E)`​​
  • ​​(2)`take()`​​
  • ​​三、應用場景​​

一、簡介

兩種降低鎖粒度的技術:
  1. 鎖分解(将一個鎖分解為兩個鎖)
  2. 鎖分段(把一個鎖分解為多個鎖)

​LinkedBlockingQueue​

​​ :先進先出,阻塞隊列。擁有​

​takeLock​

​​和​

​putLock​

​兩個鎖。

二、源碼分析

(1)​

​put(E)​

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) {
            // 加入 Condition 隊列,等待
            notFull.await();
        }
        // 入隊
        enqueue(node);
        
        // 自增,這裡用 AtomicInteger,是因為有兩個鎖
        c = count.getAndIncrement();
        // 是否滿
        if (c + 1 < capacity)
            notFull.signal(); // 喚醒 notFull Condition隊列
    } finally {
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty(); // 鎖 takeLock,喚醒 notEmpty Condition隊列
}

private void signalNotEmpty() {
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lock();
    try {
        notEmpty.signal();
    } finally {
        takeLock.unlock();
    }
}      

(2)​

​take()​

public E take() throws InterruptedException {
    E x;
    int c = -1;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly();
    try {
        // 是否有值
        while (count.get() == 0) {
            notEmpty.await();
        }
        // 出隊
        x = dequeue();
        
        // 自減
        c = count.getAndDecrement();
        if (c > 1)
            notEmpty.signal(); // 喚醒 notEmpty Condition 隊列
    } finally {
        takeLock.unlock();
    }
    if (c == capacity)
        signalNotFull();
    return x;
}      

三、應用場景

  1. ​Logger​

  2. ​Executors​