鉴于:
- 一个惰性初始化的单例类,使用双重检查锁定模式实现,所有相关
volatile
内容synchronized
都在getInstance
.ExecutorService
这个单例通过,启动异步操作 - 有七种类型的任务,每一种都由一个唯一的键标识,
- 启动任务时,它会存储在基于 的缓存中
ConcurrentHashMap
, - 当客户端请求任务时,如果缓存中的任务完成,则启动并缓存新的任务;如果它正在运行,则从缓存中检索任务并将其传递给客户端。
这是代码的摘录:
private static volatile TaskLauncher instance;
private ExecutorService threadPool;
private ConcurrentHashMap<String, Future<Object>> tasksCache;
private TaskLauncher() {
threadPool = Executors.newFixedThreadPool(7);
tasksCache = new ConcurrentHashMap<String, Future<Object>>();
}
public static TaskLauncher getInstance() {
if (instance == null) {
synchronized (TaskLauncher.class) {
if (instance == null) {
instance = TaskLauncher();
}
}
}
return instance;
}
public Future<Object> getTask(String key) {
Future<Object> expectedTask = tasksCache.get(key);
if (expectedTask == null || expectedTask.isDone()) {
synchronized (tasksCache) {
if (expectedTask == null || expectedTask.isDone()) {
// Make some stuff to create a new task
expectedTask = [...];
threadPool.execute(expectedTask);
taskCache.put(key, expectedTask);
}
}
}
return expectedTask;
}
我有一个大问题,还有一个小问题:
- 我是否需要在我的
getTask
方法中执行双重检查锁定控制?我知道ConcurrentHashMap
读操作是线程安全的,所以 myget(key)
是线程安全的,可能不需要双重检查锁定(但对此非常不确定……)。但是isDone()
Future的方法呢? - 你如何在一个
synchronized
块中选择正确的锁对象?我知道它一定不是null
,所以我首先在方法中使用TaskLauncher.class
对象,getInstance()
然后tasksCache
在方法中使用已经初始化的getTask(String key)
。事实上,这个选择有什么重要性吗?