Creating a ConcurrentHashMap that supports “snapshots”

后端 未结 3 1206
无人及你
无人及你 2020-12-17 05:22

I\'m attempting to create a ConcurrentHashMap that supports \"snapshots\" in order to provide consistent iterators, and am wondering if there\'s a more efficien

相关标签:
3条回答
  • 2020-12-17 05:53

    Solution1) What about just synchronizing on the puts, and on the iteration. That should give you a consistent snapshot.

    Solution2) Start iterating and make a boolean to say so, then override the puts, putAll so that they go into a queue, when the iteration is finished simply make those puts with the changed values.

    0 讨论(0)
  • 2020-12-17 05:58

    I've found that the ctrie is the ideal solution - it's a concurrent hash array mapped trie with constant time snapshots

    0 讨论(0)
  • 2020-12-17 06:01

    What is your actual use case that requires a special implementation? From the Javadoc of ConcurrentHashMap (emphasis added):

    Retrievals reflect the results of the most recently completed update operations holding upon their onset. ... Iterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration. They do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.

    So the regular ConcurrentHashMap.values().iterator() will give you a "consistent" iterator, but only for one-time use by a single thread. If you need to use the same "snapshot" multiple times and/or by multiple threads, I suggest making a copy of the map.

    EDIT: With the new information and the insistence for a "strongly consistent" iterator, I offer this solution. Please note that the use of a ReadWriteLock has the following implications:

    • Writes will be serialized (only one writer at a time) so write performance may be impacted.
    • Concurrent reads are allowed as long as there is no write in progress, so read performance impact should be minimal.
    • Active readers block writers but only as long as it takes to retrieve the reference to the current "snapshot". Once a thread has the snapshot, it no longer blocks writers no matter how long it takes to process the information in the snapshot.
    • Readers are blocked while any write is active; once the write finishes then all readers will have access to the new snapshot until a new write replaces it.

    Consistency is achieved by serializing the writes and making a copy of the current values on each and every write. Readers that hold a reference to a "stale" snapshot can continue to use the old snapshot without worrying about modification, and the garbage collector will reclaim old snapshots as soon as no one is using it any more. It is assumed that there is no requirement for a reader to request a snapshot from an earlier point in time.

    Because snapshots are potentially shared among multiple concurrent threads, the snapshots are read-only and cannot be modified. This restriction also applies to the remove() method of any Iterator instances created from the snapshot.

    import java.util.*;
    import java.util.concurrent.locks.*;
    
    public class StackOverflow16600019 <K, V> {
        private final ReadWriteLock locks = new ReentrantReadWriteLock();
        private final HashMap<K,V> map = new HashMap<>();
        private Collection<V> valueSnapshot = Collections.emptyList();
    
        public V put(K key, V value) {
            locks.writeLock().lock();
            try {
                V oldValue = map.put(key, value);
                updateSnapshot();
                return oldValue;
            } finally {
                locks.writeLock().unlock();
            }
        }
    
        public V remove(K key) {
            locks.writeLock().lock();
            try {
                V removed = map.remove(key);
                updateSnapshot();
                return removed;
            } finally {
                locks.writeLock().unlock();
            }
        }
    
        public Collection<V> values() {
            locks.readLock().lock();
            try {
                return valueSnapshot; // read-only!
            } finally {
                locks.readLock().unlock();
            }
        }
    
        /** Callers MUST hold the WRITE LOCK. */
        private void updateSnapshot() {
            valueSnapshot = Collections.unmodifiableCollection(
                new ArrayList<V>(map.values())); // copy
        }
    }
    
    0 讨论(0)
提交回复
热议问题