与えられた:
volatile遅延初期化シングルトン クラスはsynchronized、getInstance. このシングルトンは、ExecutorService,を介して非同期操作を開始します- タスクには 7 つのタイプがあり、それぞれが一意のキーで識別されます。
- タスクが起動されると、に基づいてキャッシュに保存されます
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;
}
1 つの大きな質問と、もう 1 つの小さな質問があります。
getTaskメソッドでロック制御をダブルチェックする必要がありますか? 私ConcurrentHashMapは読み取り操作がスレッドセーフであることを知っているので、get(key)スレッドセーフであり、ロックのダブルチェックは必要ないかもしれません (しかし、これについてはまだよくわかりません…)。しかしisDone()、Future のメソッドはどうでしょうか。synchronizedブロック内の適切なロック オブジェクトをどのように選択しますか? であってはならないことがわかっているnullので、最初に のTaskLauncher.classオブジェクトを使用しgetInstance()、次にメソッドtasksCacheで既に初期化されているを使用しますgetTask(String key)。そして、この選択は実際に重要ですか?