您的位置:首页 > 编程语言 > Java开发

java8 ConcurrentHashMap

2016-05-31 19:12 405 查看
node结构

static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;

Node(int hash, K key, V val, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.val = val;
this.next = next;
}

public final K getKey() { return key; }
public final V getValue() { return val; }
public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
public final String toString(){ return key + "=" + val; }
public final V setValue(V value) {
throw new UnsupportedOperationException();
}

public final boolean equals(Object o) {
Object k, v, u; Map.Entry<?,?> e;
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
(v = e.getValue()) != null &&
(k == key || k.equals(key)) &&
(v == (u = val) || v.equals(u)));
}

/**
* Virtualized support for map.get(); overridden in subclasses.
*/
Node<K,V> find(int h, Object k) {
Node<K,V> e = this;
if (k != null) {
do {
K ek;
if (e.hash == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
} while ((e = e.next) != null);
}
return null;
}
}
static final int MOVED     = -1; // hash for forwarding nodes   forwardNode类型节点的hash
static final int TREEBIN   = -2; // hash for roots of trees     树形节点hash

/**
     * Table initialization and resizing control.  When negative, the 负数时候是在初始化或者重建
     * table is being initialized or resized: -1 for initialization,
     * else -(1 + the number of active resizing threads).  Otherwise,
     * when table is null, holds the initial table size to use upon
     * creation, or 0 for default. After initialization, holds the
     * next element count value upon which to resize the table.
     */
    private transient volatile int sizeCtl;


put以及transfer过程:
1、不允许Null的key或者value

2、一个死循环用来put,何时put成功何时跳出,第一次put初始化table

3、tabAt(tab, i = (n - 1) & hash)找到当前node应该在table位置处的node,若是为null,不加锁利用casTabAt()方法放进去,break

4、如果这个node不是null,而是forwardNode类型,说明这个节点以及被transfer了,这使用helpTransfer(tab, f);帮助transfer,得到新的table,进行下一次循环put

5、如果找到的node不是null,也不是forwardNode类型,即找到了链表或者tree的头结点,对这个头结点加锁

遍历链表或者tree,比较key和hash,找到则替换value,到尾节点则新加一个节点

6、transfer扩容方法,允许多个线程扩容,利用了private transient volatile Node<K,V>[] nextTable;以及forwardNode

    一个线程扩容时候会把nextTable指向当前操作nextTab,另一个线程在put时候遇到forwardNode节点时候,使用helpTransfer,会先拿到nextTable,然后进入扩容方法,多个线程扩容操作的nextTable会是一个。

   每次处理完table中i出节点,就会把这处的节点置为forwardNode节点类型

  遍历到空节点,也置为forwardNode节点类型

  如果遍历到forwardNode类型,则跳过不处理

   拷贝节点以及list就跟hashmap类似,不过这个过程对头结点做了加锁

 

//原子操作
//可以理解为得到tab的i处节点
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
}
//如果tab的i处节点为c,则更新为v
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
//<span><span class="comment">设置节点位置的值</span><span>  </span></span>
static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: