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