鉴于:
- 一个惰性初始化的单例类,使用双重检查锁定模式实现,所有相关
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)。事实上,这个选择有什么重要性吗?