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.PlatformDependent;
20
21 import java.util.Collections;
22 import java.util.IdentityHashMap;
23 import java.util.Set;
24
25 import static io.netty.util.internal.InternalThreadLocalMap.UNSET;
26 import static io.netty.util.internal.InternalThreadLocalMap.VARIABLES_TO_REMOVE_INDEX;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class FastThreadLocal<V> {
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(VARIABLES_TO_REMOVE_INDEX);
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[0]);
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(VARIABLES_TO_REMOVE_INDEX);
101 Set<FastThreadLocal<?>> variablesToRemove;
102 if (v == InternalThreadLocalMap.UNSET || v == null) {
103 variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
104 threadLocalMap.setIndexedVariable(VARIABLES_TO_REMOVE_INDEX, 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(VARIABLES_TO_REMOVE_INDEX);
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 public FastThreadLocal() {
129 index = InternalThreadLocalMap.nextVariableIndex();
130 }
131
132
133
134
135 @SuppressWarnings("unchecked")
136 public final V get() {
137 InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
138 Object v = threadLocalMap.indexedVariable(index);
139 if (v != InternalThreadLocalMap.UNSET) {
140 return (V) v;
141 }
142
143 return initialize(threadLocalMap);
144 }
145
146
147
148
149 @SuppressWarnings("unchecked")
150 public final V getIfExists() {
151 InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
152 if (threadLocalMap != null) {
153 Object v = threadLocalMap.indexedVariable(index);
154 if (v != InternalThreadLocalMap.UNSET) {
155 return (V) v;
156 }
157 }
158 return null;
159 }
160
161
162
163
164
165 @SuppressWarnings("unchecked")
166 public final V get(InternalThreadLocalMap threadLocalMap) {
167 Object v = threadLocalMap.indexedVariable(index);
168 if (v != InternalThreadLocalMap.UNSET) {
169 return (V) v;
170 }
171
172 return initialize(threadLocalMap);
173 }
174
175 private V initialize(InternalThreadLocalMap threadLocalMap) {
176 V v = null;
177 try {
178 v = initialValue();
179 if (v == InternalThreadLocalMap.UNSET) {
180 throw new IllegalArgumentException("InternalThreadLocalMap.UNSET can not be initial value.");
181 }
182 } catch (Exception e) {
183 PlatformDependent.throwException(e);
184 }
185
186 threadLocalMap.setIndexedVariable(index, v);
187 addToVariablesToRemove(threadLocalMap, this);
188 return v;
189 }
190
191
192
193
194 public final void set(V value) {
195 getAndSet(value);
196 }
197
198
199
200
201 public final void set(InternalThreadLocalMap threadLocalMap, V value) {
202 getAndSet(threadLocalMap, value);
203 }
204
205
206
207
208 public V getAndSet(V value) {
209 if (value != InternalThreadLocalMap.UNSET) {
210 InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
211 return setKnownNotUnset(threadLocalMap, value);
212 }
213 return removeAndGet(InternalThreadLocalMap.getIfSet());
214 }
215
216
217
218
219 public V getAndSet(InternalThreadLocalMap threadLocalMap, V value) {
220 if (value != InternalThreadLocalMap.UNSET) {
221 return setKnownNotUnset(threadLocalMap, value);
222 }
223 return removeAndGet(threadLocalMap);
224 }
225
226
227
228
229 @SuppressWarnings("unchecked")
230 private V setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
231 V old = (V) threadLocalMap.getAndSetIndexedVariable(index, value);
232 if (old == UNSET) {
233 addToVariablesToRemove(threadLocalMap, this);
234 return null;
235 }
236 return old;
237 }
238
239
240
241
242 public final boolean isSet() {
243 return isSet(InternalThreadLocalMap.getIfSet());
244 }
245
246
247
248
249
250 public final boolean isSet(InternalThreadLocalMap threadLocalMap) {
251 return threadLocalMap != null && threadLocalMap.isIndexedVariableSet(index);
252 }
253
254
255
256
257 public final void remove() {
258 remove(InternalThreadLocalMap.getIfSet());
259 }
260
261
262
263
264
265
266 @SuppressWarnings("unchecked")
267 public final void remove(InternalThreadLocalMap threadLocalMap) {
268 removeAndGet(threadLocalMap);
269 }
270
271
272
273
274
275
276 @SuppressWarnings("unchecked")
277 private V removeAndGet(InternalThreadLocalMap threadLocalMap) {
278 if (threadLocalMap == null) {
279 return null;
280 }
281
282 Object v = threadLocalMap.removeIndexedVariable(index);
283 if (v != InternalThreadLocalMap.UNSET) {
284 removeFromVariablesToRemove(threadLocalMap, this);
285 try {
286 onRemoval((V) v);
287 } catch (Exception e) {
288 PlatformDependent.throwException(e);
289 }
290 return (V) v;
291 }
292 return null;
293 }
294
295
296
297
298 protected V initialValue() throws Exception {
299 return null;
300 }
301
302
303
304
305
306
307 protected void onRemoval(@SuppressWarnings("UnusedParameters") V value) throws Exception { }
308 }