JAVAのブロッキングキューと非ブロッキングキュー

ブロッキングキュー

BlockingQueueインターフェイスの下の各実装クラスとソースコード紹介の一部であるBlockingQueueは、さまざまなシナリオで使用する要素操作を挿入、削除、および取得するための4つの異なるメソッドを提供します。

  • 例外をスローします。キューが空またはキューがいっぱいの場合は、例外を直接スローします。
  • 特別な値を返します(nullまたはtrue / false)
  • この操作が成功するまでこの操作を待機するブロック
  • 成功するか、指定された時間が経過するまで、この操作を待機するブロック。
オペレーティング 例外をスローする 空に戻す 待機のブロック タイムアウト
インサート add(e) オファー(e) put(e) オファー(e、時間、単位)
削除する 削除する() poll() 取る() 投票(時間、単位)
リターンヘッダーを削除しないでください 素子() ピーク()
BlockingQueue,我们的关注点应该在 put(e) 和 take() 这两个方法,因为这两个方法是带阻塞的

ArrayBlockingQueue

ArrayBlockingQueueは、BlockingQueueインターフェイスの制限付きキュー実装クラスであり、最下層は配列によって実装されます。

置く

blockingQueue.put(ball);

public void put(E e) throws InterruptedException {
    
    
   checkNotNull(e);
   //获取独占锁
   final ReentrantLock lock = this.lock;
   //上锁
   lock.lockInterruptibly();
   try {
    
    
       //如果队列中的元素等于队列长度
       while (count == items.length)
           //非满阻塞,队列为空阻塞
           notFull.await();
       //如果队列中还可以存放数据,加入到队列
       enqueue(e);
   } finally {
    
    
       lock.unlock();
   }
}
private void enqueue(E x) {
    
    
    //底层使用数组实现的,数组下标赋值
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
        putIndex = 0;
    count++;
    //唤醒非空等待,就是唤醒取值等待
    notEmpty.signal();
}

blockingQueue.take()

public E take() throws InterruptedException {
    
    
    //获取锁
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
    
    
       //非空阻塞
        while (count == 0)
            notEmpty.await();
        //取队列数据
        return dequeue();
    } finally {
    
    
        lock.unlock();
    }
}
private E dequeue() {
    
    
     //取数组下标数据 老下标 置空
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    E x = (E) items[takeIndex];
    items[takeIndex] = null;
    if (++takeIndex == items.length)
        takeIndex = 0;
    count--;
    if (itrs != null)
        itrs.elementDequeued();
    //唤醒put中的阻塞线程
    notFull.signal();
    return x;
}

ソースコードは非常に単純なので、余分なものについては話さないでください

LinkedBlockingQueue

ArrayBlockingQueueとは異なり、ここでは2つのロックと2つの条件が使用されます

public void put(E e) throws InterruptedException {
    
    
     if (e == null) throw new NullPointerException();
     //用于唤醒读线程取值
     int c = -1;
     Node<E> node = new Node<E>(e);
     //获取put锁
     final ReentrantLock putLock = this.putLock;
     final AtomicInteger count = this.count;
     //上锁
     putLock.lockInterruptibly();
     try {
    
    
         //队列是否满了 满了阻塞notFull
         while (count.get() == capacity) {
    
    
             notFull.await();
         }
         //加入队列
         enqueue(node);
         c = count.getAndIncrement();
         //队列没有满 唤醒  另一个put线程
         if (c + 1 < capacity)
             notFull.signal();
     } finally {
    
    
         putLock.unlock();
     }
     //如果 c == 0,那么代表队列在这个元素入队前是空的
     if (c == 0)
         //那么所有的读线程都在等待 notEmpty 这个条件,等待唤醒,这里做一次唤醒操作
         signalNotEmpty();
 }

エンキュー

private void enqueue(Node<E> node) {
    
    
    last = last.next = node;
}
private void signalNotEmpty() {
    
    
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lock();
    try {
    
    
        notEmpty.signal();
    } finally {
    
    
        takeLock.unlock();
    }
}

取る

public E take() throws InterruptedException {
    
    
     E x;
     int c = -1;
     final AtomicInteger count = this.count;
     //take锁
     final ReentrantLock takeLock = this.takeLock;
     takeLock.lockInterruptibly();
     try {
    
    
         //如果队列等于0 阻塞住
         while (count.get() == 0) {
    
    
             notEmpty.await();
         }
         //取队列数据
         x = dequeue();
         //取前队列中的长度
         c = count.getAndDecrement();
         if (c > 1)
             //如果队列中有数据唤醒其余线程取数据
             notEmpty.signal();
     } finally {
    
    
         takeLock.unlock();
     }
      // 如果 c == capacity,那么说明在这个 take 方法发生的时候,队列是满的
    // 既然出队了一个,那么意味着队列不满了,唤醒写线程去写
     if (c == capacity)
         signalNotFull();
     return x;
 }

DelayQueue

優先ヒープに裏打ちされた時間ベースのスケジューリングキュー

PriorityBlockingQueue

優先度ヒープでサポートされる無制限の優先度キュー

ConcurrentLinkedQueue

最下層はcas +ループを使用しますが、casはループの無制限キューの追加に失敗します。
最後に、データをキューの最後に挿入します

値もcas操作なので、ここでは詳しく説明しません。大晦日に、寝て食事をする準備をします。

public boolean offer(E e) {
    
    
   checkNotNull(e);
   final Node<E> newNode = new Node<E>(e);

   for (Node<E> t = tail, p = t;;) {
    
    
       Node<E> q = p.next;
       if (q == null) {
    
    
           if (p.casNext(null, newNode)) {
    
    
               if (p != t) // hop two nodes at a time
                   casTail(t, newNode);  // Failure is OK.
               return true;
           }
       }
       else if (p == q)
           p = (t != (t = tail)) ? t : head;
       else
           p = (p != t && t != (t = tail)) ? t : q;
   }
}

おすすめ

転載: blog.csdn.net/qq_37904966/article/details/113772686