也许ConcurrentHashMap可以帮到你.顾名思义,它支持并发修改.
要只创建一个新元素,您可以执行以下操作:
private Map map = new ConcurrentHashMap<>();
private final Object lock = new Object();
public Thing getById(String id) {
Thing t = map.get(id);
if (t == null) {
synchronized(lock) {
if (!map.containsKey(id)) {
t = //create t
map.put(id, t);
}
}
}
return t;
}
一次只允许一个线程创建新的东西,但是对于现有的值,没有任何锁定.
如果你想完全避免锁定,你必须使用2个地图,但它有点令人费解,如果你真的希望很多线程不断地填充地图,那么它是值得的.对于这种情况,最好将FutureTasks与线程池一起使用,以异步方式创建对象,最大限度地减少锁定的时间(您仍需要锁定,以便只有一个线程创建新元素).
代码将是这样的:
private Map> map = new ConcurrentHashMap<>();
private final Object lock = new Object();
ExecutorService threadPool = ...;
public Thing getById(String id) {
Future t = map.get(id);
if (t == null) {
synchronized(lock) {
if (!map.containsKey(id)) {
Callable c = //create a Callable that creates the Thing
t = threadPool.submit(c);
map.put(id, t);
}
}
}
return t.get();
}
锁定仅在创建Callable所需的时间内存在,将其提交到线程池以获取Future,并将Future置于地图中. Callable将在线程池中创建元素,当它返回元素时,Future的get()方法将解锁并返回其值(对于任何等待的线程;后续调用不会锁定).