您可以考虑访问同时回收双端队列已满active.poll()
的旧元素[]的情况。ArrayDequeue.doubleCapacity()
一种可能的时间表:
- 轮询线程签出
active.isEmpty()
返回 false
- 轮询线程调用```active.pollFirst() 来访问非原子元素[]
- 一个或多个其他线程
active.addLast()
突发调用,因此active
已满并触发 doubleCapacity()
- 在 doubleCapacity() 中,elements[] 被新分配的数组替换,这样旧的 elements[] 被 GC 回收
- 轮询线程现在引用回收的元素 [] 并可能变为空。
我的猜测是,当队列不为空时,您希望避免同步轮询。为避免由于 doubleCapacity() 导致的竞争,请确保为队列分配了足够大的容量,并且在调用 addLast() 时不会满。但是,根据实际实施,您可能需要考虑其他竞赛。
以下来自 openJDK 的源代码附在后面,仅供参考。
public E pollFirst() {
int h = head;
@SuppressWarnings("unchecked")
E result = (E) elements[h];
// Element is null if deque empty
if (result == null)
return null;
elements[h] = null; // Must null out slot
head = (h + 1) & (elements.length - 1);
return result;
}
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}
private void doubleCapacity() {
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // number of elements to the right of p
int newCapacity = n << 1;
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
Object[] a = new Object[newCapacity];
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = a;
head = 0;
tail = n;
}