Copy On Write Hash Map

我们在工作的过程中,经常遇到如下的需求: 
用一个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. // read methods
  28. public int size() {
  29. return mapToRead.size();
  30. }
  31. public boolean isEmpty() {
  32. return mapToRead.isEmpty();
  33. }
  34. public boolean containsKey(Object key) {
  35. return mapToRead.containsKey(key);
  36. }
  37. public boolean containsValue(Object value) {
  38. return mapToRead.containsValue(value);
  39. }
  40. public Collection values() {
  41. return mapToRead.values();
  42. }
  43. public Set entrySet() {
  44. return mapToRead.entrySet();
  45. }
  46. public Set keySet() {
  47. return mapToRead.keySet();
  48. }
  49. public Object get(Object key) {
  50. return mapToRead.get(key);
  51. }
  52. // write methods
  53. public synchronized void clear() {
  54. mapToRead = getNewMap();
  55. }
  56. public synchronized Object remove(Object key) {
  57. Map map = copy();
  58. Object o = map.remove(key);
  59. mapToRead = map;
  60. return o;
  61. }
  62. public synchronized Object put(Object key, Object value) {
  63. Map map = copy();
  64. Object o = map.put(key, value);
  65. mapToRead = map;
  66. return o;
  67. }
  68. public synchronized void putAll(Map t) {
  69. Map map = copy();
  70. map.putAll(t);
  71. mapToRead = map;
  72. }
  73. }

这个Map读取的时候,和普通的HashMap一样快。 万艾可:www.weigecheng.com
写的时候,先把内部Map复制一份,然后在这个备份上进行修改,改完之后,再让内部Map等于这个修改后的Map。这个方法是同步保护的,避免了同时写操作。可见,写的时候,开销相当大。尽量使用 putAll() method。

你可能感兴趣的:(万艾可)