hashmap:当length=2^n时,hashcode & (length-1) == hashcode % length
http://www.iteye.com/topic/754887
http://www.iteye.com/topic/539465
http://www.blogjava.net/xylz/archive/2010/07/20/326584.html
解析ConcurrentLinkedQueue
http://www.blogjava.net/xylz/archive/2010/07/23/326934.html
清单1 入队列操作
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
Node<E> n = new Node<E>(e, null);
for (;;) {
Node<E> t = tail;
Node<E> s = t.getNext();
if (t == tail) {
if (s == null) {
if (t.casNext(s, n)) {//将n修改成为尾节点t的下一个节点
casTail(t, n);//将尾节点指针tail后移,指向n,使n成为尾节点
return true;
}
} else {
casTail(t, s);//将尾节点指针tail指向s,使s成为尾节点
}
}
}
}
清单1 描述的是入队列的过程。整个过程是这样的。
- 获取尾节点t,以及尾节点的下一个节点s。如果尾节点没有被别人修改,也就是t==tail,进行2,否则进行1。
- 如果s不为空,也就是说此时尾节点后面还有元素,那么就需要把尾节点往后移,进行1。否则进行3。
- 修改尾节点的下一个节点为新节点,如果成功就修改尾节点,返回true。否则进行1。
从操作3中可以看到是先修改尾节点的下一个节点,然后才修改尾节点位置的,所以这才有操作2中为什么获取到的尾节点的下一个节点不为空的原因。
特别需要说明的是,对尾节点的tail的操作需要换成临时变量t和s,一方面是为了去掉volatile变量的可变性,另一方面是为了减少volatile的性能影响。