Copy On Write Hash Map

来源:互联网 发布:双色球数据统计中心 编辑:程序博客网 时间:2024/04/28 20:13


Copy On Write Hash Map 


来源:http://www.xymyeah.com/269.html

我们在工作的过程中,经常遇到如下的需求: 
用一个Map存放常用的Object,这个Map的并发读取的频率很高,而写入的频率很低,一般只在初始化、或重新装装载的时候写入。读写冲突虽然很少发生,不过一旦发生,Map的内部结构就可能乱掉,所以,我们不得不为Map加上同步锁。 
我们可以采用Copy On Write的机制,来加强Map的读取速度。 
Copy On Write是这样一种机制。当我们读取共享数据的时候,直接读取,不需要同步。当我们修改数据的时候,我们就把当前数据Copy一份副本,然后在这个副本上进行修改,完成之后,再用修改后的副本,替换掉原来的数据。这种方法就叫做Copy On Write。 
Oracle等关系数据库的数据修改就采用Copy On Write的模式。Copy On Write模式对并发读取的支持很好,但是在并发修改的时候,会有版本冲突的问题。可能有多个线程同时修改同一份数据,那么就同时存在多个修改副本,这多个修改副本可能会相互覆盖,导致修改丢失。因此,Oracle等数据库通常会引入版本检查机制。即增加一个版本号字段,来检测是否存在并发修改。相似的版本控制机制存在于CVS、SVN等版本控制工具中。 
在我们的Copy On Write Map中,我们只需要让新数据覆盖旧数据就可以了,因此不需要考虑版本控制的问题。这就大大简化了我们的实现。 
基本思路就是让读和写操作分别在不同的Map上进行,每次写完之后,再把两个Map同步。代码如下: 
Java代码  收藏代码
  1. /* 
  2.  * Copy On Write Map 
  3.  *  
  4.  * Write is expensive. 
  5.  * Read is fast as pure HashMap. 
  6.  * 
  7.  * Note: extra info is removed for free use 
  8.  */  
  9. import java.lang.Compiler;  
  10. import java.util.Collection;  
  11. import java.util.Map;  
  12. import java.util.Set;  
  13. import java.util.HashMap;  
  14. import java.util.Collections;  
  15.  public class ReadWriteMap implements Map {  
  16.     protected volatile Map mapToRead = getNewMap();  
  17.     // you can override it as new TreeMap();  
  18.     protected Map getNewMap(){  
  19.         return new HashMap();  
  20.     }  
  21.     // copy mapToWrite to mapToRead  
  22.     protected Map copy(){  
  23.         Map newMap = getNewMap();  
  24.         newMap.putAll(mapToRead);  
  25.         return newMap;  
  26.     }  
  27.    
  28.     // read methods  
  29.     public int size() {  
  30.         return mapToRead.size();  
  31.     }  
  32.     public boolean isEmpty() {  
  33.         return mapToRead.isEmpty();  
  34.     }  
  35.    
  36.     public boolean containsKey(Object key) {  
  37.         return mapToRead.containsKey(key);  
  38.     }  
  39.    
  40.     public boolean containsValue(Object value) {  
  41.         return mapToRead.containsValue(value);  
  42.     }  
  43.    
  44.     public Collection values() {  
  45.         return mapToRead.values();  
  46.     }  
  47.    
  48.     public Set entrySet() {  
  49.         return mapToRead.entrySet();  
  50.     }  
  51.    
  52.     public Set keySet() {  
  53.         return mapToRead.keySet();  
  54.     }  
  55.    
  56.     public Object get(Object key) {  
  57.         return mapToRead.get(key);  
  58.     }  
  59.    
  60.     // write methods  
  61.     public synchronized void clear() {  
  62.         mapToRead = getNewMap();  
  63.     }  
  64.    
  65.     public synchronized Object remove(Object key) {  
  66.         Map map = copy();  
  67.         Object o = map.remove(key);  
  68.         mapToRead = map;  
  69.         return o;  
  70.     }  
  71.    
  72.     public synchronized Object put(Object key, Object value) {  
  73.         Map map = copy();   
  74.         Object o = map.put(key, value);  
  75.         mapToRead = map;  
  76.         return o;  
  77.     }  
  78.    
  79.     public synchronized void putAll(Map t) {  
  80.         Map map = copy();   
  81.         map.putAll(t);  
  82.         mapToRead = map;  
  83.     }  
  84. }  

这个Map读取的时候,和普通的HashMap一样快。 

写的时候,先把内部Map复制一份,然后在这个备份上进行修改,改完之后,再让内部Map等于这个修改后的Map。这个方法是同步保护的,避免了同时写操作。可见,写的时候,开销相当大。尽量使用 putAll() method。 


http://www.xymyeah.com/269.html