问题
Many threads may populate a HashMap
, in some cases I need to wait (block) until an object exists in the HashMap, such as:
BlockingConcurrentHashMap map = new BlockingConcurrentHashMap();
Object x = map.getAndWait(key, 1000); //(object_to_get, max_delay_ms)
Wondering if such a thing exists already, I hate re-inventing wheels.
回答1:
As far as I know, there is no 'Transfer Map' available. Though the creation of one in theory isn't too difficult.
public class TransferMap<K,V> implements Map<K,V>{
@GuardedBy("lock")
private final HashMap<K,V> backingMap = new HashMap<K,V>();
private final Object lock = new Object();
public V getAndWait(Object key){
synchronized(lock){
V value = null;
do{
value = backingMap.get(key);
if(value == null) lock.wait();
}while(value == null);
}
return value;
}
public V put(K key, V value){
synchronized(lock){
V value = backingMap.put(key,value);
lock.notifyAll();
}
return value;
}
}
There are obvious exclusions in this class. Not to mentioned the lock coarsening; needless to say it won't perform great, but you should get the idea of what is going on
回答2:
Blockingmap4j will suit your requirement just right.
You can find it at https://github.com/sarveswaran-m/blockingMap4j/wiki/
Since granular locks are used in the implementation, performance will not be severely degraded.
PS
This is a rather late answer on a question that is 2 years old. Since, there is no way to send a private message to the author of the question, am replying here.
回答3:
Improvement on John's impl, with aimed notify(), instead of "thundering herd", which is especially bad when nobody is waiting on an inserted key
HashMap<K,Object> locks = new HashMap<>();
put(key, value)
synchronized(locks)
backingMap.put(key,value);
lock = locks.get(key);
if(lock!=null)
lock.notifyAll();
getAndWait(key)
// not hard, but pretty verbose
回答4:
You can populate your Hashtable
with java.util.concurrent.FutureTask<ObjReturned>
s at the start with all the tasks you need to compute. You then use a thread pool to start executing your FutureTask
s. You can get your results asynchronously with ObjReturned obj = hashtable.get(key).get()
, which will wait if the FutureTask
in question is not done yet.
You probably don't want one single thread to retrieve the results since it might wait on the task that will turn out to finish last. You could have multiple retrieval threads, or you could cycle through the keys when you wait too long for one task (there is a method FutureTask.get(waitTime, timeUnit)
).
回答5:
I'm not sure what your question is. Do you want to wait for the value when it is not in the map? You want the producer-consumer pattern of BlockingQueue on a map. If it is that I don't know anything similar in the JRE or anywhere else.
Google guava MapMaker allows you to make a computing map, that is a Map that creates the value if it does not exist by using a factory with type Function<Key, Value>. If several threads reach that situation at the same time one creates the value and the rest blocks waiting for it. I know it's not producer-consumer but is what I can offer.
来源:https://stackoverflow.com/questions/6389122/does-a-hashmap-with-a-getandwait-method-exist-e-g-a-blockingconcurrenthashma