Overview
- Netty的无锁队列
- 适用于单消费者多生产者场景
- A lock-free concurrent single-consumer multi-producer Queue
数据结构
里面有三种需要提一下的数据结构
Node, DefaultNode, Ref
1. Node: 声明了的next, volatile型, 还有AtomicReferenceFieldUpdater对next进行修改
2. DefaultNode: Node的实现类, 声明了value
3. Ref: 分为TailRef和HeadRef, 分别声明了volatile的tailRef和headRef引用…还有各自的AtomicReferenceFieldUpdater
实现
Offer
public boolean offer(E value) {
if (value == null) {
throw new NullPointerException("value");
}
final MpscLinkedQueueNode<E> newTail;
if (value instanceof MpscLinkedQueueNode) {
newTail = (MpscLinkedQueueNode<E>) value;
newTail.setNext(null);
} else {
newTail = new DefaultNode<E>(value);
}
MpscLinkedQueueNode<E> oldTail = getAndSetTailRef(newTail);
oldTail.setNext(newTail);
return true;
}
Poll
private MpscLinkedQueueNode<E> peekNode() {
MpscLinkedQueueNode<E> head = headRef();
MpscLinkedQueueNode<E> next = head.next();
if (next == null && head != tailRef()) {
// if tail != head this is not going to change until consumer makes progress
// we can avoid reading the head and just spin on next until it shows up
//
// See https://github.com/akka/akka/pull/15596
do {
next = head.next();
} while (next == null);
}
return next;
}
public E poll() {
final MpscLinkedQueueNode<E> next = peekNode();
if (next == null) {
return null;
}
// next becomes a new head.
MpscLinkedQueueNode<E> oldHead = headRef();
// Similar to 'headRef.node = next', but slightly faster (storestore vs loadstore)
// See: http://robsjava.blogspot.com/2013/06/a-faster-volatile.html
// See: http://psy-lob-saw.blogspot.com/2012/12/atomiclazyset-is-performance-win-for.html
lazySetHeadRef(next);
// Break the linkage between the old head and the new head.
oldHead.unlink();
return next.clearMaybe();
}
伪共享
long p00, p01, p02, p03, p04, p05, p06, p07;
long p30, p31, p32, p33, p34, p35, p36, p37;
队列中有定义这样一组变量, 据说是关于伪共享, 尚未研习…
有Link: 从Java视角理解系统结构(三)伪共享