MpscLinkedQueue7与MpscLinkedQueue8
public class MpscLinkedQueue7<E> extends MpscLinkedQueue<E> {
@SuppressWarnings("unchecked")
protected final LinkedQueueNode<E> xchgProducerNode(LinkedQueueNode<E> newVal) {
Object oldVal;
do {
oldVal = producerNode;
} while(!UNSAFE.compareAndSwapObject(this, P_NODE_OFFSET, oldVal, newVal));
return (LinkedQueueNode<E>) oldVal;
}
}
使用UNSAFE.compareAndSwapObject对producerNode进行CAS重试,这是比较正统的做法。
public class MpscLinkedQueue8<E> extends MpscLinkedQueue<E> {
@SuppressWarnings("unchecked")
protected final LinkedQueueNode<E> xchgProducerNode(LinkedQueueNode<E> newVal) {
return (LinkedQueueNode<E>) UNSAFE.getAndSetObject(this, P_NODE_OFFSET, newVal);
}
}
getAndSetObject是在Jdk8中基于CAS扩展出来的方法,它的具体实现为:
public final Object getAndSetObject(Object o, long offset, Object newValue) {
Object v;
do {
v = getObjectVolatile(o, offset);
} while (!compareAndSwapObject(o, offset, v, newValue));
return v;
}
是先通过offset进行volatile获取这个位置上的oldValue,然后进行cas重试。也能实现和上面相同的效果,只是使用了java8包装过的方法, cas部分不需要自己写。
我们继续查看这个方法的使用位置就对为什么这样定义很清楚了。
public abstract class MpscLinkedQueue<E> extends BaseLinkedQueue<E> {
/**
* Construct the implementation based on availability of getAndSet intrinsic.
*
* @return the right queue for you!
*/
public static <E> MpscLinkedQueue<E> newMpscLinkedQueue() {
if (UnsafeAccess.SUPPORTS_GET_AND_SET) {
return new MpscLinkedQueue8<E>();
}
else {
return new MpscLinkedQueue7<E>();
}
}
protected MpscLinkedQueue() {
consumerNode = new LinkedQueueNode<E>();
xchgProducerNode(consumerNode);// this ensures correct construction: StoreLoad
}
protected abstract LinkedQueueNode<E> xchgProducerNode(LinkedQueueNode<E> nextNode);
它是通过UnsafeAccess.SUPPORTSGETAND_SET的值来判断是使用MpscLinkedQueue8还是MpscLinkedQueue7的。
其中org.jctools.util.UnsafeAccess的代码如下:
public class UnsafeAccess {
public static final boolean SUPPORTS_GET_AND_SET;
public static final Unsafe UNSAFE;
static {
Unsafe instance;
try {
final Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
instance = (Unsafe) field.get(null);
} catch (Exception ignored) {
// Some platforms, notably Android, might not have a sun.misc.Unsafe
// implementation with a private `theUnsafe` static instance. In this
// case we can try and call the default constructor, which proves
// sufficient for Android usage.
try {
Constructor<Unsafe> c = Unsafe.class.getDeclaredConstructor();
c.setAccessible(true);
instance = c.newInstance();
} catch (Exception e) {
SUPPORTS_GET_AND_SET = false;
throw new RuntimeException(e);
}
}
boolean getAndSetSupport = false;
try {
Unsafe.class.getMethod("getAndSetObject", Object.class, Long.TYPE,Object.class);
getAndSetSupport = true;
} catch (Exception ignored) {
}
UNSAFE = instance;
SUPPORTS_GET_AND_SET = getAndSetSupport;
}
}
可以SUPPORTSGETAND_SET是用来判断是否支持getAndSet用的。
jdk7中直接使用MpscLinkedQueue7,在java8中使用MpscLinkedQueue8,也可以使用MpscLinkedQueue.newMpscLinkedQueue()来创建。