Данный:
- Ленивый инициализированный одноэлементный класс, реализованный с шаблоном блокировки двойной проверки со всеми соответствующими
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
является потокобезопасным для операций чтения, поэтому мойget(key)
является потокобезопасным и может не нуждаться в блокировке с двойной проверкой (но пока совершенно не уверен в этом…). А как насчет методаisDone()
Future? - Как выбрать правильный объект блокировки в блоке
synchronized
? Я знаю, что это не должно бытьnull
, поэтому я сначала использую объектTaskLauncher.class
вgetInstance()
, а затем уже инициализированныйtasksCache
в методеgetTask(String key)
. И имеет ли этот выбор какое-то значение на самом деле?
getTask
. Вы можете запустить две или более одинаковых задач, потому что вы не проверяете, что находится в кеше внутри вашего синхронизированного блока. Вам нужно извлечь свежее кешированное значение внутри вашего синхронизированного блока, иначе двойная проверка не сработает. - person Pavel Horal   schedule 14.02.2014ConcurrentHashMap
не имеет отношения к тому, нужно ли вам использовать DCL. Это то, о чем вы спрашивали в своем Q1. - person Stephen C   schedule 14.02.2014