ブロッキングキュー
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;
}
}