1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.util.concurrent;
17
18 import io.netty.util.internal.InternalThreadLocalMap;
19 import io.netty.util.internal.ObjectCleaner;
20 import io.netty.util.internal.PlatformDependent;
21
22 import java.util.Collections;
23 import java.util.IdentityHashMap;
24 import java.util.Set;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class FastThreadLocal<V> {
46
47 private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
48
49
50
51
52
53
54 public static void removeAll() {
55 InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
56 if (threadLocalMap == null) {
57 return;
58 }
59
60 try {
61 Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
62 if (v != null && v != InternalThreadLocalMap.UNSET) {
63 @SuppressWarnings("unchecked")
64 Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
65 FastThreadLocal<?>[] variablesToRemoveArray =
66 variablesToRemove.toArray(new FastThreadLocal[variablesToRemove.size()]);
67 for (FastThreadLocal<?> tlv: variablesToRemoveArray) {
68 tlv.remove(threadLocalMap);
69 }
70 }
71 } finally {
72 InternalThreadLocalMap.remove();
73 }
74 }
75
76
77
78
79 public static int size() {
80 InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
81 if (threadLocalMap == null) {
82 return 0;
83 } else {
84 return threadLocalMap.size();
85 }
86 }
87
88
89
90
91
92
93
94 public static void destroy() {
95 InternalThreadLocalMap.destroy();
96 }
97
98 @SuppressWarnings("unchecked")
99 private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
100 Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
101 Set<FastThreadLocal<?>> variablesToRemove;
102 if (v == InternalThreadLocalMap.UNSET || v == null) {
103 variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
104 threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
105 } else {
106 variablesToRemove = (Set<FastThreadLocal<?>>) v;
107 }
108
109 variablesToRemove.add(variable);
110 }
111
112 private static void removeFromVariablesToRemove(
113 InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
114
115 Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
116
117 if (v == InternalThreadLocalMap.UNSET || v == null) {
118 return;
119 }
120
121 @SuppressWarnings("unchecked")
122 Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
123 variablesToRemove.remove(variable);
124 }
125
126 private final int index;
127
128 private final int cleanerFlagIndex;
129
130 public FastThreadLocal() {
131 index = InternalThreadLocalMap.nextVariableIndex();
132 cleanerFlagIndex = InternalThreadLocalMap.nextVariableIndex();
133 }
134
135
136
137
138 @SuppressWarnings("unchecked")
139 public final V get() {
140 InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
141 Object v = threadLocalMap.indexedVariable(index);
142 if (v != InternalThreadLocalMap.UNSET) {
143 return (V) v;
144 }
145
146 V value = initialize(threadLocalMap);
147 registerCleaner(threadLocalMap);
148 return value;
149 }
150
151 private void registerCleaner(final InternalThreadLocalMap threadLocalMap) {
152 Thread current = Thread.currentThread();
153 if (FastThreadLocalThread.willCleanupFastThreadLocals(current) ||
154 threadLocalMap.indexedVariable(cleanerFlagIndex) != InternalThreadLocalMap.UNSET) {
155 return;
156 }
157
158
159 threadLocalMap.setIndexedVariable(cleanerFlagIndex, Boolean.TRUE);
160
161
162
163 ObjectCleaner.register(current, new Runnable() {
164 @Override
165 public void run() {
166 remove(threadLocalMap);
167
168
169
170 }
171 });
172 }
173
174
175
176
177
178 @SuppressWarnings("unchecked")
179 public final V get(InternalThreadLocalMap threadLocalMap) {
180 Object v = threadLocalMap.indexedVariable(index);
181 if (v != InternalThreadLocalMap.UNSET) {
182 return (V) v;
183 }
184
185 return initialize(threadLocalMap);
186 }
187
188 private V initialize(InternalThreadLocalMap threadLocalMap) {
189 V v = null;
190 try {
191 v = initialValue();
192 } catch (Exception e) {
193 PlatformDependent.throwException(e);
194 }
195
196 threadLocalMap.setIndexedVariable(index, v);
197 addToVariablesToRemove(threadLocalMap, this);
198 return v;
199 }
200
201
202
203
204 public final void set(V value) {
205 if (value != InternalThreadLocalMap.UNSET) {
206 InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
207 if (setKnownNotUnset(threadLocalMap, value)) {
208 registerCleaner(threadLocalMap);
209 }
210 } else {
211 remove();
212 }
213 }
214
215
216
217
218 public final void set(InternalThreadLocalMap threadLocalMap, V value) {
219 if (value != InternalThreadLocalMap.UNSET) {
220 setKnownNotUnset(threadLocalMap, value);
221 } else {
222 remove(threadLocalMap);
223 }
224 }
225
226
227
228
229 private boolean setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
230 if (threadLocalMap.setIndexedVariable(index, value)) {
231 addToVariablesToRemove(threadLocalMap, this);
232 return true;
233 }
234 return false;
235 }
236
237
238
239
240 public final boolean isSet() {
241 return isSet(InternalThreadLocalMap.getIfSet());
242 }
243
244
245
246
247
248 public final boolean isSet(InternalThreadLocalMap threadLocalMap) {
249 return threadLocalMap != null && threadLocalMap.isIndexedVariableSet(index);
250 }
251
252
253
254 public final void remove() {
255 remove(InternalThreadLocalMap.getIfSet());
256 }
257
258
259
260
261
262
263 @SuppressWarnings("unchecked")
264 public final void remove(InternalThreadLocalMap threadLocalMap) {
265 if (threadLocalMap == null) {
266 return;
267 }
268
269 Object v = threadLocalMap.removeIndexedVariable(index);
270 removeFromVariablesToRemove(threadLocalMap, this);
271
272 if (v != InternalThreadLocalMap.UNSET) {
273 try {
274 onRemoval((V) v);
275 } catch (Exception e) {
276 PlatformDependent.throwException(e);
277 }
278 }
279 }
280
281
282
283
284 protected V initialValue() throws Exception {
285 return null;
286 }
287
288
289
290
291 protected void onRemoval(@SuppressWarnings("UnusedParameters") V value) throws Exception { }
292 }