zoukankan      html  css  js  c++  java
  • ConcurrentHashMap之实现细节3

    实现细节

    修改操作

    先来看下删除操作remove(key)。

    Java代码
    1. public V remove(Object key) {  
    2. hash = hash(key.hashCode());  
    3.     return segmentFor(hash).remove(key, hash, null);  
    4. }  
    public V remove(Object key) { int hash = hash(key.hashCode()); return segmentFor(hash).remove(key, hash, null); }

    整个操作是先定位到段,然后委托给段的remove操作。当多个删除操作并发进行时,只要它们所在的段不相同,它们就可以同时进行。下面是Segment的remove方法实现:

    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%20%20%20%20%20V%20remove(Object%20key%2C%20int%20hash%2C%20Object%20value)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20lock()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20c%20%3D%20count%20-%201%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20HashEntry%3CK%2CV%3E%5B%5D%20tab%20%3D%20table%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20index%20%3D%20hash%20%26%20(tab.length%20-%201)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20HashEntry%3CK%2CV%3E%20first%20%3D%20tab%5Bindex%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20HashEntry%3CK%2CV%3E%20e%20%3D%20first%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20while%20(e%20!%3D%20null%20%26%26%20(e.hash%20!%3D%20hash%20%7C%7C%20!key.equals(e.key)))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e%20%3D%20e.next%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20V%20oldValue%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(e%20!%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20V%20v%20%3D%20e.value%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(value%20%3D%3D%20null%20%7C%7C%20value.equals(v))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20oldValue%20%3D%20v%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20All%20entries%20following%20removed%20node%20can%20stay%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20in%20list%2C%20but%20all%20preceding%20ones%20need%20to%20be%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20cloned.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%2BmodCount%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20HashEntry%3CK%2CV%3E%20newFirst%20%3D%20e.next%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20(HashEntry%3CK%2CV%3E%20p%20%3D%20first%3B%20p%20!%3D%20e%3B%20p%20%3D%20p.next)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20newFirst%20%3D%20new%20HashEntry%3CK%2CV%3E(p.key%2C%20p.hash%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20newFirst%2C%20p.value)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tab%5Bindex%5D%20%3D%20newFirst%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count%20%3D%20c%3B%20%2F%2F%20write-volatile%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20oldValue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20unlock()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D" src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" lk_mediaid="lk_juiceapp_mediaPopup_1236652704298" lk_media="yes">
    1. V remove(Object key, int hash, Object value) {  
    2.      lock();  
    3.     try {  
    4.         int c = count - 1;  
    5.          HashEntry<K,V>[] tab = table;  
    6.         int index = hash & (tab.length - 1);  
    7.          HashEntry<K,V> first = tab[index];  
    8.          HashEntry<K,V> e = first;  
    9.         while (e != null && (e.hash != hash || !key.equals(e.key)))  
    10.              e = e.next;  
    11.   
    12.          V oldValue = null;  
    13.         if (e != null) {  
    14.              V v = e.value;  
    15.             if (value == null || value.equals(v)) {  
    16.                  oldValue = v;  
    17.                 // All entries following removed node can stay  
    18.                 // in list, but all preceding ones need to be  
    19.                 // cloned.  
    20.                  ++modCount;  
    21.                  HashEntry<K,V> newFirst = e.next;  
    22.                 for (HashEntry<K,V> p = first; p != e; p = p.next)  
    23.                      newFirst = new HashEntry<K,V>(p.key, p.hash,  
    24.                                                    newFirst, p.value);  
    25.                  tab[index] = newFirst;  
    26.                  count = c; // write-volatile  
    27.              }  
    28.          }  
    29.         return oldValue;  
    30.      } finally {  
    31.          unlock();  
    32.      }  
    33. }  
    V remove(Object key, int hash, Object value) { lock(); try { int c = count - 1; HashEntry<K,V>[] tab = table; int index = hash & (tab.length - 1); HashEntry<K,V> first = tab[index]; HashEntry<K,V> e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue = null; if (e != null) { V v = e.value; if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay // in list, but all preceding ones need to be // cloned. ++modCount; HashEntry<K,V> newFirst = e.next; for (HashEntry<K,V> p = first; p != e; p = p.next) newFirst = new HashEntry<K,V>(p.key, p.hash, newFirst, p.value); tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } }

    整个操作是在持有段锁的情况下执行的,空白行之前的行主要是定位到要删除的节点e。接下来,如果不存在这个节点就直接返回null,否则就要将e前面的结点复制一遍,尾结点指向e的下一个结点。e后面的结点不需要复制,它们可以重用。下面是个示意图,我直接从这个网站 上复制的(画这样的图实在是太麻烦了,如果哪位有好的画图工具,可以推荐一下)。

    删除元素之前:

    a hash chain before an element is removed

    删除元素3之后:

    the chain with element 3 removed

    第二个图其实有点问题,复制的结点中应该是值为2的结点在前面,值为1的结点在后面,也就是刚好和原来结点顺序相反,还好这不影响我们的讨论。

    整个remove实现并不复杂,但是需要注意如下几点。第一,当要删除的结点存在时,删除的最后一步操作要将count的值减一。这必须是最后一步 操作,否则读取操作可能看不到之前对段所做的结构性修改。第二,remove执行的开始就将table赋给一个局部变量tab,这是因为table是 volatile变量,读写volatile变量的开销很大。编译器也不能对volatile变量的读写做任何优化,直接多次访问非volatile实例 变量没有多大影响,编译器会做相应优化。

    接下来看put操作,同样地put操作也是委托给段的put方法。下面是段的put方法:

    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%20%20%20%20%20V%20put(K%20key%2C%20int%20hash%2C%20V%20value%2C%20boolean%20onlyIfAbsent)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20lock()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20c%20%3D%20count%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(c%2B%2B%20%3E%20threshold)%20%2F%2F%20ensure%20capacity%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rehash()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20HashEntry%3CK%2CV%3E%5B%5D%20tab%20%3D%20table%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20index%20%3D%20hash%20%26%20(tab.length%20-%201)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20HashEntry%3CK%2CV%3E%20first%20%3D%20tab%5Bindex%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20HashEntry%3CK%2CV%3E%20e%20%3D%20first%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20while%20(e%20!%3D%20null%20%26%26%20(e.hash%20!%3D%20hash%20%7C%7C%20!key.equals(e.key)))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e%20%3D%20e.next%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20V%20oldValue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(e%20!%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20oldValue%20%3D%20e.value%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(!onlyIfAbsent)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.value%20%3D%20value%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20oldValue%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%2BmodCount%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tab%5Bindex%5D%20%3D%20new%20HashEntry%3CK%2CV%3E(key%2C%20hash%2C%20first%2C%20value)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count%20%3D%20c%3B%20%2F%2F%20write-volatile%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20oldValue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20unlock()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D" src="http://www.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" lk_mediaid="lk_juiceapp_mediaPopup_1236652704304" lk_media="yes">
    1. V put(K key, int hash, V value, boolean onlyIfAbsent) {  
    2.      lock();  
    3.     try {  
    4.         int c = count;  
    5.         if (c++ > threshold) // ensure capacity  
    6.              rehash();  
    7.          HashEntry<K,V>[] tab = table;  
    8.         int index = hash & (tab.length - 1);  
    9.          HashEntry<K,V> first = tab[index];  
    10.          HashEntry<K,V> e = first;  
    11.         while (e != null && (e.hash != hash || !key.equals(e.key)))  
    12.              e = e.next;  
    13.   
    14.          V oldValue;  
    15.         if (e != null) {  
    16.              oldValue = e.value;  
    17.             if (!onlyIfAbsent)  
    18.                  e.value = value;  
    19.          }  
    20.         else {  
    21.              oldValue = null;  
    22.              ++modCount;  
    23.              tab[index] = new HashEntry<K,V>(key, hash, first, value);  
    24.              count = c; // write-volatile  
    25.          }  
    26.         return oldValue;  
    27.      } finally {  
    28.          unlock();  
    29.      }  
    30. }  
    V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { int c = count; if (c++ > threshold) // ensure capacity rehash(); HashEntry<K,V>[] tab = table; int index = hash & (tab.length - 1); HashEntry<K,V> first = tab[index]; HashEntry<K,V> e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue; if (e != null) { oldValue = e.value; if (!onlyIfAbsent) e.value = value; } else { oldValue = null; ++modCount; tab[index] = new HashEntry<K,V>(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); } }
  • 相关阅读:
    MySQL 数据库主从复制架构
    程序员的双十一
    MySQL 数据库事务与复制
    十字路口的程序员
    瞬息之间与时间之门
    HDFS 与 GFS 的设计差异
    HDFS 异常处理与恢复
    HDFS Client 设计实现解析
    HDFS DataNode 设计实现解析
    HDFS NameNode 设计实现解析
  • 原文地址:https://www.cnblogs.com/danghuijian/p/4400693.html
Copyright © 2011-2022 走看看