JCTools是一款对jdk并发数据结构进行增强的并发工具,主要提供了非阻塞Map以及无锁Queue的增强数据结构,关于NonBlockingHashMap
源码分析我写了篇文章。
如果还不了解CAS,可以参考这个博客http://blog.csdn.net/hsuxu/article/details/9467651
主要说下JCTools中的Queue,和jdk中的Queue比性能有很大的提升,主要实现利用了CAS和填充缓存行(避免伪共享),典型的空间换时间,然后我在百度时很多文章千篇一律不知道是不是抄袭,最蛋疼的是很多文章都提到“使用lazySet替代volatile set”这个主要是指Unsafe中的putOrderedObject,jdk并发包下常用 Unsafe的几个方法putOrderedObject,putObjectVolatile,compareAndSwapObject等,回到lazySet问题,很多文章都会提到一句话“这种性能提升是有代价的,虽然廉价,也就是写后结果并不会被其他线程看到,甚至是自己的线程,通常是几纳秒后被其他线程看到,lazySet的写在实践上来延迟是纳秒级,这个时间比较短,所以代价可以忍受。”,如果这玩意有延迟将是致命的或者有其他方法解决,所以我去看了下代码,mmp,这些文章乱写一通,尼玛,下面挑选一个类MpmcArrayQueue分析下源码具体看下是如何利用CAS的:
public E poll() {
long[] sBuffer = this.sequenceBuffer;
long mask = this.mask;
long pIndex = -1L;
long cIndex;
long seq;
long seqOffset;
long expectedSeq;
do {
cIndex = this.lvConsumerIndex();
seqOffset = calcSequenceOffset(cIndex, mask);
seq = this.lvSequence(sBuffer, seqOffset);
expectedSeq = cIndex + 1L;
if (seq < expectedSeq) {
if (cIndex >= pIndex && cIndex == (pIndex = this.lvProducerIndex())) {
return null;
}
seq = expectedSeq + 1L;
}
} while(seq > expectedSeq || !this.casConsumerIndex(cIndex, cIndex + 1L));
long offset = calcElementOffset(cIndex, mask);
E e = UnsafeRefArrayAccess.lpElement(this.buffer, offset);
UnsafeRefArrayAccess.soElement(this.buffer, offset, (Object)null);
this.soSequence(sBuffer, seqOffset, cIndex + mask + 1L);
return e;
}
上面方法是poll方法,看下11行的lvConsumerIndex方法是获取消费者索引的,这个字段是volatile修饰的,关于volatile就不用多讲了吧,22行casConsumerIndex方法底层调用了compareAndSwapLong方法,26行soElement底层调用了putOrderedObject,看到了吗,是调用putOrderedObject将数据存储,使用读取volatile字段保证数据可见性。非“使用lazySet替代volatile set”。
offer方法是类似的,就不贴代码了。但愿少一些文章抄袭。。