How to declare a mutable list as part of a hashmap?

I have a variable:

ConcurrentHashMap<String, List<AnObjectType>> mapOfList; 

The list that I understand is not thread safe. But I don’t want to use the Synchronized keyword, because I really need concurrent read access and write synchronization to the list, not a read and write lock.

Therefore, I would usually declare Volatile for a variable as follows:

 volatile List<AnObjectType> varName; 

(Although in this case, I believe that these are links to the volatile link in the list, but I want both the link to the list and the contents of the list to be unstable.)

But how can I do this in the ConcurrentHashMap construct, given that I do not declare the list as a variable somewhere, but inside the method?

i.e. The list is created inside the method:

 if (!mapOfList.containsKey("ListA")) { List<AnObjectType> listA=new ArrayList<AnObjectType>(); mapOfList.put("ListA", listA); } 

and access to the list is carried out by another method within the same class:

 List<AnObjectType> listA=mapOfList.get("ListA"); if (listA!=null) { // Do something concurrent with listA. } 

Sub Question: Will there be something like this work at all?

ConcurrentHashMap<String,List<AtomicReference<AnObjectType>>>>

List operations development:

The list will be available through several threads that will be read almost constantly. Recording will be called up under certain conditions. So what I want is simultaneous access to the contents of the list with rarely performed operations on the contents of the list, which should be reflected by all reads after the write operation.

+4
source share
3 answers

Use ConcurrentMap#putIfAbsent to create a List and access all the lists in the lazy recipient:

 List<AnObjectType> getList(String key) { if (!mapOfList.containsKey(key)) { // This list might not end up being the one that gets returned, but // that OK mapOfList.putIfAbsent(key, new CopyOnWriteArrayList<AnObjectType>()); } return mapOfList.get(key); } 

CopyOnWriteArrayList should provide you with synchronized performance.

+5
source

You can look at java.util.concurrent.locks , in particular ReentrantReadWriteLock . Javadocs package says

The ReadWriteLock interface likewise defines locks that can be shared among readers, but exclusively for writers. Only one implementation, ReentrantReadWriteLock, is provided as it covers most standard usage contexts. But programmers can create their own implementations to cover non-standard requirements.

Javadocs for ReentrantReadWriteLock says

ReentrantReadWriteLocks can be used to improve concurrency in some uses of certain kinds of collections. Usually it’s worth it when the collections are expected to be large, access to them will be more reader threads than writer flows, and entails overhead operations that outweigh the synchronization overhead.

and contains an example using TreeMap .

The general idea is that you create an instance of ReentrantReadWriteLock for each instance of the collection. You are then provided with one instance of Lock for read operations and another for write operations. Then you manually control the lock during access methods.

The following is an unverified implementation that should support your use case.

 import java.util.AbstractList; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class RWList<E> extends AbstractList<E> { private final List<E> list = new ArrayList<E>(); private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); @Override public E set(int index, E element) { w.lock(); try { return list.set(index, element); } finally { w.unlock(); } } @Override public void add(int index, E element) { w.lock(); try { list.add(index, element); } finally { w.unlock(); } } @Override public E remove(int index) { w.lock(); try { return list.remove(index); } finally { w.unlock(); } } @Override public E get(int index) { r.lock(); try { return list.get(index); } finally { r.unlock(); } } @Override public int size() { r.lock(); try { return list.size(); } finally { r.unlock(); } } } 
+1
source

The vector class is synchronized by ArrayList, you can also use Collections.synchronizedList(new ArrayList()) .

0
source

Source: https://habr.com/ru/post/1385503/


All Articles