最简单和经典的解决方案是覆盖最老元素的有界环形缓冲区。
实现相当简单。您需要一个AtomicInteger/Long for index + AtomicReferenceArray,并且您有一个无锁通用堆栈,仅有两种方法offer/poll
,no size()
。大多数并发/无锁结构有w/size()的困难。非覆盖堆栈可以具有O(1),但是具有put上的分配。
东西沿着线:
package bestsss.util;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReferenceArray;
public class ConcurrentArrayStack<E> extends AtomicReferenceArray<E>{
//easy to extend and avoid indirections,
//feel free to contain the ConcurrentArrayStack if feel purist
final AtomicLong index = new AtomicLong(-1);
public ConcurrentArrayStack(int length) {
super(length); //returns
}
/**
* @param e the element to offer into the stack
* @return the previously evicted element
*/
public E offer(E e){
for (;;){
long i = index.get();
//get the result, CAS expect before the claim
int idx = idx(i+1);
E result = get(idx);
if (!index.compareAndSet(i, i+1))//claim index spot
continue;
if (compareAndSet(idx, result, e)){
return result;
}
}
}
private int idx(long idx){//can/should use golden ratio to spread the index around and reduce false sharing
return (int)(idx%length());
}
public E poll(){
for (;;){
long i = index.get();
if (i==-1)
return null;
int idx = idx(i);
E result = get(idx);//get before the claim
if (!index.compareAndSet(i, i-1))//claim index spot
continue;
if (compareAndSet(idx, result, null)){
return result;
}
}
}
}
最后音符:具有模操作 是一个昂贵和功率为2的容量是优选的,经由&length()-1
(也守卫VS长溢出)。
”非阻塞 - 如果双端队列为空,则检索不应该阻塞,它也不应该返回null/throw异常是双端队列已满。 - 从空列表中检索项目时会发生什么?既不例外,也不阻塞,也不返回'null'?可以返回 – 2010-10-23 09:15:45
检索'null'。如果deque是_full_,那么应该添加该项目,并且旧项目 - 丢弃 – Bozho 2010-10-23 09:24:30
只是一个说明LinkedBlockingDeque不是并发的。 – bestsss 2011-12-06 18:40:54