Does java have a "LinkedConcurrentHashMap" data structure?

JavaData Structures

Java Problem Overview


I need a data structure that is a LinkedHashMap and is thread safe.

How can I do that ?

Java Solutions


Solution 1 - Java

You can wrap the map in a Collections.synchronizedMap to get a synchronized hashmap that maintains insertion order. This is not as efficient as a ConcurrentHashMap (and doesn't implement the extra interface methods of ConcurrentMap) but it does get you the (somewhat) thread safe behavior.

Even the mighty Google Collections doesn't appear to have solved this particular problem yet. However, there is one project that does try to tackle the problem.

I say somewhat on the synchronization, because iteration is still not thread safe in the sense that concurrent modification exceptions can happen.

Solution 2 - Java

There's a number of different approaches to this problem. You could use:

Collections.synchronizedMap(new LinkedHashMap());

as the other responses have suggested but this has several gotchas you'll need to be aware of. Most notably is that you will often need to hold the collections synchronized lock when iterating over the collection, which in turn prevents other threads from accessing the collection until you've completed iterating over it. (See Java theory and practice: Concurrent collections classes). For example:

synchronized(map) {
    for (Object obj: map) {
        // Do work here
    }
}

Using

new ConcurrentHashMap();

is probably a better choice as you won't need to lock the collection to iterate over it.

Finally, you might want to consider a more functional programming approach. That is you could consider the map as essentially immutable. Instead of adding to an existing Map, you would create a new one that contains the contents of the old map plus the new addition. This sounds pretty bizarre at first, but it is actually the way Scala deals with concurrency and collections

Solution 3 - Java

There is one implementation available under Google code. A quote from their site:

> A high performance version of java.util.LinkedHashMap for use as a software cache. > > Design > >

  • A concurrent linked list runs through a ConcurrentHashMap to provide eviction ordering.
  • Supports insertion and access ordered eviction policies (FIFO, LRU, and Second Chance).

Solution 4 - Java

You can use a ConcurrentSkipListMap, only available in Java SE/EE 6 or later. It is order presevering in that keys are sorted according to their natural ordering. You need to have a Comparator or make the keys Comparable objects. In order to mimik a linked hash map behavior (iteration order is the order in time in which entries were added) I implemented my key objects to always compare to be greater than a given other object unless it is equal (whatever that is for your object). A wrapped synchronized linked hash map did not suffice because as stated in http://www.ibm.com/developerworks/java/library/j-jtp07233.html: "The synchronized collections wrappers, synchronizedMap and synchronizedList, are sometimes called conditionally thread-safe -- all individual operations are thread-safe, but sequences of operations where the control flow depends on the results of previous operations may be subject to data races. The first snippet in Listing 1 shows the common put-if-absent idiom -- if an entry does not already exist in the Map, add it. Unfortunately, as written, it is possible for another thread to insert a value with the same key between the time the containsKey() method returns and the time the put() method is called. If you want to ensure exactly-once insertion, you need to wrap the pair of statements with a synchronized block that synchronizes on the Map m."

So what only helps is a ConcurrentSkipListMap which is 3-5 times slower than a normal ConcurrentHashMap.

Solution 5 - Java

Collections.synchronizedMap(new LinkedHashMap())

Solution 6 - Java

Since the ConcurrentHashMap offers a few important extra methods that are not in the Map interface, simply wrapping a LinkedHashMap with a synchronizedMap won't give you the same functionality, in particular, they won't give you anything like the putIfAbsent(), replace(key, oldValue, newValue) and remove(key, oldValue) methods which make the ConcurrentHashMap so useful.

Unless there's some apache library that has implemented what you want, you'll probably have to use a LinkedHashMap and provide suitable synchronized{} blocks of your own.

Solution 7 - Java

I just tried synchronized bounded LRU Map based on insertion order LinkedConcurrentHashMap; with Read/Write Lock for synchronization. So when you are using iterator; you have to acquire WriteLock to avoid ConcurrentModificationException.
This is better than Collections.synchronizedMap.

public class LinkedConcurrentHashMap<K, V> {

    private LinkedHashMap<K, V> linkedHashMap = null;
    private final int cacheSize;  
    private ReadWriteLock readWriteLock = null;

    public LinkedConcurrentHashMap(LinkedHashMap<K, V> psCacheMap, int size) {
		this.linkedHashMap  = psCacheMap;
		cacheSize = size;
		readWriteLock=new ReentrantReadWriteLock();
    }
    
    public void put(K key, V value) throws SQLException{
	    Lock writeLock=readWriteLock.writeLock();
	    try{
            writeLock.lock();
    	    if(linkedHashMap.size() >= cacheSize && cacheSize > 0){
   		        K oldAgedKey = linkedHashMap.keySet().iterator().next();
   		        remove(oldAgedKey);
    	    }
    	    linkedHashMap.put(key, value);
		}finally{
    		writeLock.unlock();
	    }
    }
    
    public V get(K key){
    	Lock readLock=readWriteLock.readLock();
    	try{
    		readLock.lock();
    		return linkedHashMap.get(key);
    	}finally{
    		readLock.unlock();
    	}
    }
   
    public boolean containsKey(K key){
    	Lock readLock=readWriteLock.readLock();
    	try{
    		readLock.lock();
    		return linkedHashMap.containsKey(key);
    	}finally{
    		readLock.unlock();
    	}
    }
    
    public V remove(K key){
    	Lock writeLock=readWriteLock.writeLock();
		try{
			writeLock.lock();
			return linkedHashMap.remove(key);
		}finally{
			writeLock.unlock();
		}
    }
    
    public ReadWriteLock getLock(){
    	return readWriteLock;
    }
    
    public Set<Map.Entry<K, V>> entrySet(){
    	return linkedHashMap.entrySet();
    }
}

Solution 8 - Java

The answer is pretty much no, there's nothing equivalent to a ConcurrentHashMap that is sorted (like the LinkedHashMap). As other people pointed out, you can wrap your collection using Collections.synchronizedMap(-yourmap-) however this will not give you the same level of fine grained locking. It will simply block the entire map on every operation.

Your best bet is to either use synchronized around any access to the map (where it matters, of course. You may not care about dirty reads, for example) or to write a wrapper around the map that determines when it should or should not lock.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter LeeView Question on Stackoverflow
Solution 1 - JavaYishaiView Answer on Stackoverflow
Solution 2 - JavahohonuuliView Answer on Stackoverflow
Solution 3 - JavaAndrey AdamovichView Answer on Stackoverflow
Solution 4 - JavaPaulView Answer on Stackoverflow
Solution 5 - JavaDavid CrawshawView Answer on Stackoverflow
Solution 6 - JavaAdrian PronkView Answer on Stackoverflow
Solution 7 - JavaKanagavelu SugumarView Answer on Stackoverflow
Solution 8 - JavaMalaxeurView Answer on Stackoverflow