-
Notifications
You must be signed in to change notification settings - Fork 4
/
WeakThreadLocalReference.java
77 lines (64 loc) · 2.59 KB
/
WeakThreadLocalReference.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package de.invesdwin.util.concurrent.reference;
import java.util.Optional;
import javax.annotation.concurrent.ThreadSafe;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import io.netty.util.concurrent.FastThreadLocal;
/**
* WARNING: Instances of ThreadLocal objects should always be defined in static variables or else the threadLocal
* instances might cause memory leaks.
*
* Use WeakThreadLocalReference instead for instance thread locals without memory leaks.
*/
@ThreadSafe
public class WeakThreadLocalReference<V> implements IMutableReference<V> {
private static final FastThreadLocal<LoadingCache<Object, IMutableReference<Optional<Object>>>> THREAD_LOCAL = new FastThreadLocal<LoadingCache<Object, IMutableReference<Optional<Object>>>>() {
@Override
protected LoadingCache<Object, IMutableReference<Optional<Object>>> initialValue() throws Exception {
final LoadingCache<Object, IMutableReference<Optional<Object>>> map = Caffeine.newBuilder()
.weakKeys()
.<Object, IMutableReference<Optional<Object>>> build((key) -> {
return new MutableReference<Optional<Object>>();
});
return map;
}
};
private final Object key = new Object();
protected V initialValue() {
return null;
}
@SuppressWarnings("unchecked")
@Override
public V get() {
final LoadingCache<Object, IMutableReference<Optional<Object>>> map = THREAD_LOCAL.get();
final IMutableReference<Optional<Object>> reference = map.get(key);
final Optional<V> optional = (Optional<V>) reference.get();
if (optional != null) {
return optional.orElse(null);
} else {
final V initialValue = initialValue();
reference.set(Optional.ofNullable(initialValue));
return initialValue;
}
}
@Override
public void set(final V value) {
final LoadingCache<Object, IMutableReference<Optional<Object>>> map = THREAD_LOCAL.get();
if (value == null) {
map.invalidate(key);
} else {
final IMutableReference<Optional<Object>> reference = map.get(key);
reference.set(Optional.ofNullable(value));
}
}
@Override
public V getAndSet(final V value) {
final V get = get();
set(value);
return get;
}
public void remove() {
final LoadingCache<Object, IMutableReference<Optional<Object>>> map = THREAD_LOCAL.get();
map.invalidate(key);
}
}