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。
相關文章
相關標籤/搜索