1 package org.pojomatic.internal;
2
3 import java.util.concurrent.ConcurrentHashMap;
4 import java.util.concurrent.ConcurrentMap;
5
6
7
8
9
10
11
12
13 public abstract class SelfPopulatingMap<K, V> {
14
15 public V get(final K key) {
16 V value = valueMap.get(key);
17 if (value == null) {
18 final Object mutex = new Object();
19 synchronized (mutex) {
20 Object existingMutex = mutexMap.putIfAbsent(key, mutex);
21 if (existingMutex == null) {
22 return tryCreatingValue(key);
23 }
24 else {
25 synchronized (existingMutex) {
26 V oldValue = valueMap.get(key);
27
28 return oldValue != null ? oldValue : tryCreatingValue(key);
29 }
30 }
31 }
32 }
33 return value;
34 }
35
36
37
38
39
40
41
42
43 protected abstract V create(K key);
44
45 private V tryCreatingValue(K key) {
46 V value = create(key);
47 valueMap.put(key, value);
48 return value;
49 }
50
51
52
53
54 private final ConcurrentMap<K, V> valueMap = new ConcurrentHashMap<>();
55
56
57
58
59 private final ConcurrentMap<K, Object> mutexMap = new ConcurrentHashMap<>();
60 }
61