2014-10-05 3 views
2

im, пишущий кусок кода, который нуждается в согласованном итераторе времени в момент выполнения ConcurrentHashMap.Итерационные гарантии последовательности ConcurrentHashMap

Документов есть это, чтобы сказать о итераторе последовательности:

гарантированно пройти элементы, как они существовали на строительство ровно один раз, и могут (но не гарантируются) отражать любые изменения, проведенные после строительства

, но это немного отрывочно («может»). существуют ли какие-либо конкретные гарантии, кроме того, которые могут быть связаны с ConcurrentHashMap?

Если нет, есть ли другая параллельная реализация карты, которая обеспечивает лучшие гарантии? (То же самое-нить точка-в-времени консистенция)

+0

Если вы перестанете рассматривать проблемы реализации, вы поймете, что согласованность по времени не может быть обеспечена без блокировки (вы должны блокировать при копировании моментального снимка) и могут быть без проблем * с * блокировкой. Лично я бы не подумал дважды, прежде чем перейти к схеме блокировки здесь. –

+0

@MarkoTopolnik - im no expert, но я думаю, что в теории вы можете реализовать моментальные снимки с использованием атомистики, не прибегая к блокировке. Я знаю, что эти методы используются определенными параллельными картами для изменения размера «в фоновом режиме». – radai

+0

. Неизменяемая реализация, которая всегда поддерживает моментальные копии и копии структур при каждой записи, предоставит вам ожидаемую гарантию в рутине, но к изменяемой реализации как «ConcurrentHashMap», это не происходит естественным образом. –

ответ

2

обеспечивающем вы хотите + очень большой набор данных будет включать в себя несколько операций механизма или снимки запирающие:

Snapshot<K, V> viewport = map.lockSnapshot(); 
try { 
    ... // work with version-fixed viewport. 
} finally { 
    map.unlockSnapshot(viewport); 
} 

Возможно, вам нужна транзакционная память с ключом? Взгляните на решения GridGain, у них есть такая функциональность (и намного выше).

+0

им (все еще), пытаясь избежать полномасштабных магазинов TX. до сих пор мне удалось создать код вокруг этого (http://codereview.stackexchange.com/questions/64890/threadsafe-hashmap-with-snapshot-support), но я действительно надеюсь услышать, что есть библиотека/хак, что я просто не сделал найти. – radai

+0

пару лет назад я не нашел такую ​​библиотеку (пытался решить подобную проблему). все алгоритмы ведут либо к ручному управлению моментальными снимками (как вы реализуете), либо к полным хранилищам tx. У меня есть один вопрос: если сделать копию вашей карты приведет к «выходу из кучи» - может быть, вы что-то делаете не так? – ursa

+0

размер ввода огромный. его часть проблемной области, а не артефакт моего дизайна. что я мог бы сделать (что я пытаюсь избежать), приносит в полномасштабный магазин, например rockdb или mapdb и т. д. – radai

0

Вы можете использовать реализацию карты копирования при записи:

import java.util.Collection; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
import java.util.Set; 
import java.util.concurrent.atomic.AtomicReference; 

/** 
* A thread-safe version of {@link Map} in which all operations that change the 
* Map are implemented by making a new copy of the underlying Map. 
* <p/> 
* While the creation of a new Map can be expensive, this class is designed for 
* cases in which the primary function is to read data from the Map, not to 
* modify the Map. Therefore the operations that do not cause a change to this 
* class happen quickly and concurrently. 
* 
* @author <a href="mailto:[email protected]">Kuzma Deretuke</a> 
*/ 
public class CopyOnWriteHashMap<K, V> implements Map<K, V>, Cloneable { 
    private AtomicReference<Map<K, V>> internalMap = new AtomicReference<Map<K, V>>(); 

    /** 
    * Creates a new instance of CopyOnWriteHashMap. 
    */ 
    public CopyOnWriteHashMap() { 
     internalMap.set(new HashMap<K, V>()); 
    } 

    /** 
    * Creates a new instance of CopyOnWriteHashMap with the specified initial size. 
    * 
    * @param initialCapacity The initial size of the Map. 
    */ 
    public CopyOnWriteHashMap(int initialCapacity) { 
     internalMap.set(new HashMap<K, V>(initialCapacity)); 
    } 

    /** 
    * Creates a new instance of CopyOnWriteHashMap in which the initial data, 
    * being held by this map, is contained in the supplied map. 
    * 
    * @param data A Map containing the initial contents to be placed into this class. 
    */ 
    public CopyOnWriteHashMap(Map<K, V> data) { 
     internalMap.set(new HashMap<K, V>(data)); 
    } 

    @Override 
    public V put(K key, V value) { 
     Map<K, V> oldMap; 
     Map<K, V> newMap; 
     V val; 
     do { 
      oldMap = internalMap.get(); 
      newMap = new HashMap<K, V>(oldMap); 
      val = newMap.put(key, value); 
     } 
     while (!internalMap.compareAndSet(oldMap, newMap)); 
     return val; 
    } 

    @Override 
    public V remove(Object key) { 
     Map<K, V> oldMap; 
     Map<K, V> newMap; 
     V val; 
     do { 
      oldMap = internalMap.get(); 
      newMap = new HashMap<K, V>(oldMap); 
      val = newMap.remove(key); 
     } 
     while (!internalMap.compareAndSet(oldMap, newMap)); 
     return val; 
    } 

    @Override 
    public void putAll(Map<? extends K, ? extends V> newData) { 
     Map<K, V> oldMap; 
     Map<K, V> newMap; 
     do { 
      oldMap = internalMap.get(); 
      newMap = new HashMap<K, V>(oldMap); 
      newMap.putAll(newData); 
     } 
     while (!internalMap.compareAndSet(oldMap, newMap)); 
    } 

    @Override 
    public void clear() { 
     internalMap.set(new HashMap<K, V>()); 
    } 

    // 
    // Below are methods that do not modify the internal map 
    //   

    @Override 
    public int size() { 
     return internalMap.get().size(); 
    } 

    @Override 
    public boolean isEmpty() { 
     return internalMap.get().isEmpty(); 
    } 

    @Override 
    public boolean containsKey(Object key) { 
     return internalMap.get().containsKey(key); 
    } 

    @Override 
    public boolean containsValue(Object value) { 
     return internalMap.get().containsValue(value); 
    } 

    @Override 
    public V get(Object key) { 
     return internalMap.get().get(key); 
    } 

    @Override 
    public Set<K> keySet() { 
     return internalMap.get().keySet(); 
    } 

    @Override 
    public Collection<V> values() { 
     return internalMap.get().values(); 
    } 

    @Override 
    public Set<Entry<K, V>> entrySet() { 
     return internalMap.get().entrySet(); 
    } 

    @Override 
    public int hashCode() { 
     return internalMap.get().hashCode(); 
    } 

    @Override 
    public boolean equals(Object o) { 
     return internalMap.get().equals(o); 
    } 

    @Override 
    public String toString() { 
     Map<K, V> map = internalMap.get(); 
     Iterator<Entry<K, V>> i = map.entrySet().iterator(); 
     if (!i.hasNext()) 
      return "{}"; 

     StringBuilder sb = new StringBuilder(); 
     sb.append('{'); 
     for (; ;) { 
      Entry<K, V> e = i.next(); 
      K key = e.getKey(); 
      V value = e.getValue(); 
      sb.append(key == this ? "(this Map)" : (key == map ? "(internal Map)" : key)); 
      sb.append('='); 
      sb.append(value == this ? "(this Map)" : (value == map ? "(internal Map)" : value)); 
      if (!i.hasNext()) 
       return sb.append('}').toString(); 
      sb.append(',').append(' '); 
     } 
    } 

    @Override 
    public Object clone() { 
     try { 
      CopyOnWriteHashMap<K, V> clone = (CopyOnWriteHashMap<K, V>) super.clone(); 
      clone.internalMap = new AtomicReference<Map<K, V>>(new HashMap<K, V>(internalMap.get())); 
      return clone; 
     } 
     catch (CloneNotSupportedException e) { 
      throw new InternalError(); 
     } 
    } 
} 
+0

Информация о лицензии, относящейся к этому файлу, приведена в https://svn.apache.org/repos/asf/mina/sandbox/mwebb/mina/src/main/java/org/apache/mina/util/CopyOnWriteMap.java – Marco13

+0

Это класс похож на mina CopyOnWriteMap, но это моя собственная неблокирующая версия. – ursa

+0

Моя карта, как ожидается, будет очень большой (миллионы записей). эта копия выглядит как самоубийство для меня – radai

Смежные вопросы