java-并发-ConcurrentHashMap高并发机制-jdk1.8
Posted 07H_JH
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java-并发-ConcurrentHashMap高并发机制-jdk1.8相关的知识,希望对你有一定的参考价值。
JDK8的版本,与JDK6的版本有很大的差异。实现线程安全的思想也已经完全变了,它摒弃了Segment(锁段)的概念,而是启用了一种全新的方式实现,利用CAS算法。它沿用了与它同时期的HashMap版本的思想,底层依然由“数组”+链表+红黑树的方式思想,但是为了做到并发,又增加了很多辅助的类,例如TreeBin,Traverser等对象内部类。CAS算法实现无锁化的修改值的操作,他可以大大降低锁代理的性能消耗。这个算法的基本思想就是不断地去比较当前内存中的变量值与你指定的一个变量值是否相等,如果相等,则接受你指定的修改的值,否则拒绝你的操作。因为当前线程中的值已经不是最新的值,你的修改很可能会覆盖掉其他线程修改的结果。这一点与乐观锁,SVN的思想是比较类似的。
ConcurrentHashMap是conccurrent家族中的一个类,由于它可以高效地支持并发操作,以及被广泛使用,经典的开源框架Spring的底层数据结构就是使用ConcurrentHashMap实现的。与同是线程安全的老大哥HashTable相比,它已经更胜一筹,因此它的锁更加细化,而不是像HashTable一样为几乎每个方法都添加了synchronized锁,这样的锁无疑会影响到性能。
本文的分析的源码是JDK8的版本,与JDK6的版本有很大的差异。实现线程安全的思想也已经完全变了,它摒弃了Segment(锁段)的概念,而是启用了一种全新的方式实现,利用CAS算法。它沿用了与它同时期的HashMap版本的思想,底层依然由“数组”+链表+红黑树的方式思想,但是为了做到并发,又增加了很多辅助的类,例如TreeBin,Traverser等对象内部类。
1 重要的属性
首先来看几个重要的属性,与HashMap相同的就不再介绍了,这里重点解释一下sizeCtl这个属性。可以说它是ConcurrentHashMap中出镜率很高的一个属性,因为它是一个控制标识符,在不同的地方有不同用途,而且它的取值不同,也代表不同的含义。
- 负数代表正在进行初始化或扩容操作
- -1代表正在初始化
- -N 表示有N-1个线程正在进行扩容操作
- 正数或0代表hash表还没有被初始化,这个数值表示初始化或下一次进行扩容的大小,这一点类似于扩容阈值的概念。还后面可以看到,它的值始终是当前ConcurrentHashMap容量的0.75倍,这与loadfactor是对应的。
- /**
- * 盛装Node元素的数组 它的大小是2的整数次幂
- * Size is always a power of two. Accessed directly by iterators.
- */
- transient volatile Node<K,V>[] table;
- /**
- * 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.
- hash表初始化或扩容时的一个控制位标识量。
- 负数代表正在进行初始化或扩容操作
- -1代表正在初始化
- -N 表示有N-1个线程正在进行扩容操作
- 正数或0代表hash表还没有被初始化,这个数值表示初始化或下一次进行扩容的大小
- */
- private transient volatile int sizeCtl;
- // 以下两个是用来控制扩容的时候 单线程进入的变量
- /**
- * The number of bits used for generation stamp in sizeCtl.
- * Must be at least 6 for 32bit arrays.
- */
- private static int RESIZE_STAMP_BITS = 16;
- /**
- * The bit shift for recording size stamp in sizeCtl.
- */
- private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
- /*
- * Encodings for Node hash fields. See above for explanation.
- */
- static final int MOVED = -1; // hash值是-1,表示这是一个forwardNode节点
- static final int TREEBIN = -2; // hash值是-2 表示这时一个TreeBin节点
2 重要的内部类
2.1 Node
Node是最核心的内部类,它包装了key-value键值对,所有插入ConcurrentHashMap的数据都包装在这里面。它与HashMap中的定义很相似,但是但是有一些差别它对value和next属性设置了volatile同步锁,它不允许调用setValue方法直接改变Node的value域,它增加了find方法辅助map.get()方法。
[java] view plain copy
- static class Node<K,V> implements Map.Entry<K,V>
- final int hash;
- final K key;
- volatile V val;//带有同步锁的value
- volatile Node<K,V> next;//带有同步锁的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;
- //不允许直接改变value的值
- 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;
- 这个Node内部类与HashMap中定义的Node类很相似,但是有一些差别
- 它对value和next属性设置了Java并发编程:并发容器之ConcurrentHashMap
Java并发编程:并发容器之ConcurrentHashMap(转载)
Java并发:并发集合ConcurrentHashMap的源码分析