ConcurrentHashMap之实现细节2

数据结构

关于Hash表的基础数据结构,这里不想做过多的探讨。Hash表的一个很重要方面就是如何解决hash冲突,ConcurrentHashMap 和HashMap使用相同的方式,都是将hash值相同的节点放在一个hash链中。与HashMap不同的是,ConcurrentHashMap使用 多个子Hash表,也就是段(Segment)。下面是ConcurrentHashMap的数据成员:

Java代码 <embed height="15" width="14" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" allowscriptaccess="always" quality="high" flashvars="clipboard=public%20class%20ConcurrentHashMap%3CK%2C%20V%3E%20extends%20AbstractMap%3CK%2C%20V%3E%0A%20%20%20%20%20%20%20%20implements%20ConcurrentMap%3CK%2C%20V%3E%2C%20Serializable%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20Mask%20value%20for%20indexing%20into%20segments.%20The%20upper%20bits%20of%20a%0A%20%20%20%20%20*%20key's%20hash%20code%20are%20used%20to%20choose%20the%20segment.%0A%20%20%20%20%20*%2F%0A%20%20%20%20final%20int%20segmentMask%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20Shift%20value%20for%20indexing%20within%20segments.%0A%20%20%20%20%20*%2F%0A%20%20%20%20final%20int%20segmentShift%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20The%20segments%2C%20each%20of%20which%20is%20a%20specialized%20hash%20table%0A%20%20%20%20%20*%2F%0A%20%20%20%20final%20Segment%3CK%2CV%3E%5B%5D%20segments%3B%0A%7D" src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" lk_mediaid="lk_juiceapp_mediaPopup_1236652704279" lk_media="yes">
  1. public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>  
  2.         implements ConcurrentMap<K, V>, Serializable {  
  3.     /**
  4.       * Mask value for indexing into segments. The upper bits of a
  5.       * key's hash code are used to choose the segment.
  6.       */  
  7.     final int segmentMask;  
  8.   
  9.     /**
  10.       * Shift value for indexing within segments.
  11.       */  
  12.     final int segmentShift;  
  13.   
  14.     /**
  15.       * The segments, each of which is a specialized hash table
  16.       */  
  17.     final Segment<K,V>[] segments;  
  18. }  
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable { /** * Mask value for indexing into segments. The upper bits of a * key's hash code are used to choose the segment. */ final int segmentMask; /** * Shift value for indexing within segments. */ final int segmentShift; /** * The segments, each of which is a specialized hash table */ final Segment<K,V>[] segments; }

所有的成员都是final的,其中segmentMask和segmentShift主要是为了定位段,参见上面的segmentFor方法。

每个Segment相当于一个子Hash表,它的数据成员如下:

Java代码 <embed height="15" width="14" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" allowscriptaccess="always" quality="high" flashvars="clipboard=%20%20%20%20static%20final%20class%20Segment%3CK%2CV%3E%20extends%20ReentrantLock%20implements%20Serializable%20%7B%0Aprivate%20static%20final%20long%20serialVersionUID%20%3D%202249069246763182397L%3B%0A%20%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20%20*%20The%20number%20of%20elements%20in%20this%20segment's%20region.%0A%20%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%20transient%20volatile%20int%20count%3B%0A%0A%20%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20%20*%20Number%20of%20updates%20that%20alter%20the%20size%20of%20the%20table.%20This%20is%0A%20%20%20%20%20%20%20%20%20*%20used%20during%20bulk-read%20methods%20to%20make%20sure%20they%20see%20a%0A%20%20%20%20%20%20%20%20%20*%20consistent%20snapshot%3A%20If%20modCounts%20change%20during%20a%20traversal%0A%20%20%20%20%20%20%20%20%20*%20of%20segments%20computing%20size%20or%20checking%20containsValue%2C%20then%0A%20%20%20%20%20%20%20%20%20*%20we%20might%20have%20an%20inconsistent%20view%20of%20state%20so%20(usually)%0A%20%20%20%20%20%20%20%20%20*%20must%20retry.%0A%20%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%20transient%20int%20modCount%3B%0A%0A%20%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20%20*%20The%20table%20is%20rehashed%20when%20its%20size%20exceeds%20this%20threshold.%0A%20%20%20%20%20%20%20%20%20*%20(The%20value%20of%20this%20field%20is%20always%20%3Ctt%3E(int)(capacity%20*%0A%20%20%20%20%20%20%20%20%20*%20loadFactor)%3C%2Ftt%3E.)%0A%20%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%20transient%20int%20threshold%3B%0A%0A%20%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20%20*%20The%20per-segment%20table.%0A%20%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%20transient%20volatile%20HashEntry%3CK%2CV%3E%5B%5D%20table%3B%0A%0A%20%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20%20*%20The%20load%20factor%20for%20the%20hash%20table.%20%20Even%20though%20this%20value%0A%20%20%20%20%20%20%20%20%20*%20is%20same%20for%20all%20segments%2C%20it%20is%20replicated%20to%20avoid%20needing%0A%20%20%20%20%20%20%20%20%20*%20links%20to%20outer%20object.%0A%20%20%20%20%20%20%20%20%20*%20%40serial%0A%20%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%20final%20float%20loadFactor%3B%0A%7D" src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" lk_mediaid="lk_juiceapp_mediaPopup_1236652704286" lk_media="yes">
  1.     static final class Segment<K,V> extends ReentrantLock implements Serializable {  
  2. private static final long serialVersionUID = 2249069246763182397L;  
  3.         /**
  4.           * The number of elements in this segment's region.
  5.           */  
  6.         transient volatile int count;  
  7.   
  8.         /**
  9.           * Number of updates that alter the size of the table. This is
  10.           * used during bulk-read methods to make sure they see a
  11.           * consistent snapshot: If modCounts change during a traversal
  12.           * of segments computing size or checking containsValue, then
  13.           * we might have an inconsistent view of state so (usually)
  14.           * must retry.
  15.           */  
  16.         transient int modCount;  
  17.   
  18.         /**
  19.           * The table is rehashed when its size exceeds this threshold.
  20.           * (The value of this field is always <tt>(int)(capacity *
  21.           * loadFactor)</tt>.)
  22.           */  
  23.         transient int threshold;  
  24.   
  25.         /**
  26.           * The per-segment table.
  27.           */  
  28.         transient volatile HashEntry<K,V>[] table;  
  29.   
  30.         /**
  31.           * The load factor for the hash table.   Even though this value
  32.           * is same for all segments, it is replicated to avoid needing
  33.           * links to outer object.
  34.           * @serial
  35.           */  
  36.         final float loadFactor;  
  37. }  
static final class Segment<K,V> extends ReentrantLock implements Serializable { private static final long serialVersionUID = 2249069246763182397L; /** * The number of elements in this segment's region. */ transient volatile int count; /** * Number of updates that alter the size of the table. This is * used during bulk-read methods to make sure they see a * consistent snapshot: If modCounts change during a traversal * of segments computing size or checking containsValue, then * we might have an inconsistent view of state so (usually) * must retry. */ transient int modCount; /** * The table is rehashed when its size exceeds this threshold. * (The value of this field is always <tt>(int)(capacity * * loadFactor)</tt>.) */ transient int threshold; /** * The per-segment table. */ transient volatile HashEntry<K,V>[] table; /** * The load factor for the hash table. Even though this value * is same for all segments, it is replicated to avoid needing * links to outer object. * @serial */ final float loadFactor; }

count用来统计该段数据的个数,它是volatile,它用来协调修改和读取操作,以保证读取操作能够读取到几乎最新的修改。协调方式是这样的,每次 修改操作做了结构上的改变,如增加/删除节点(修改节点的值不算结构上的改变),都要写count值,每次读取操作开始都要读取count的值。这利用了 Java 5中对volatile语义的增强,对同一个volatile变量的写和读存在happens-before关系。modCount统计段结构改变的次 数,主要是为了检测对多个段进行遍历过程中某个段是否发生改变,在讲述跨段操作时会还会详述。threashold用来表示需要进行rehash的界限 值。table数组存储段中节点,每个数组元素是个hash链,用HashEntry表示。table也是volatile,这使得能够读取到最新的 table值而不需要同步。loadFactor表示负载因子。

你可能感兴趣的:(ConcurrentHashMap之实现细节2)