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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public class FastThreadLocal<V> {
45
46 private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
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(variablesToRemoveIndex);
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(variablesToRemoveIndex);
100 Set<FastThreadLocal<?>> variablesToRemove;
101 if (v == InternalThreadLocalMap.UNSET || v == null) {
102 variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
103 threadLocalMap.setIndexedVariable(variablesToRemoveIndex, 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(variablesToRemoveIndex);
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 } catch (Exception e) {
179 PlatformDependent.throwException(e);
180 }
181
182 threadLocalMap.setIndexedVariable(index, v);
183 addToVariablesToRemove(threadLocalMap, this);
184 return v;
185 }
186
187
188
189
190 public final void set(V value) {
191 if (value != InternalThreadLocalMap.UNSET) {
192 InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
193 setKnownNotUnset(threadLocalMap, value);
194 } else {
195 remove();
196 }
197 }
198
199
200
201
202 public final void set(InternalThreadLocalMap threadLocalMap, V value) {
203 if (value != InternalThreadLocalMap.UNSET) {
204 setKnownNotUnset(threadLocalMap, value);
205 } else {
206 remove(threadLocalMap);
207 }
208 }
209
210
211
212
213 private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
214 if (threadLocalMap.setIndexedVariable(index, value)) {
215 addToVariablesToRemove(threadLocalMap, this);
216 }
217 }
218
219
220
221
222 public final boolean isSet() {
223 return isSet(InternalThreadLocalMap.getIfSet());
224 }
225
226
227
228
229
230 public final boolean isSet(InternalThreadLocalMap threadLocalMap) {
231 return threadLocalMap != null && threadLocalMap.isIndexedVariableSet(index);
232 }
233
234
235
236
237 public final void remove() {
238 remove(InternalThreadLocalMap.getIfSet());
239 }
240
241
242
243
244
245
246 @SuppressWarnings("unchecked")
247 public final void remove(InternalThreadLocalMap threadLocalMap) {
248 if (threadLocalMap == null) {
249 return;
250 }
251
252 Object v = threadLocalMap.removeIndexedVariable(index);
253 removeFromVariablesToRemove(threadLocalMap, this);
254
255 if (v != InternalThreadLocalMap.UNSET) {
256 try {
257 onRemoval((V) v);
258 } catch (Exception e) {
259 PlatformDependent.throwException(e);
260 }
261 }
262 }
263
264
265
266
267 protected V initialValue() throws Exception {
268 return null;
269 }
270
271
272
273
274
275
276 protected void onRemoval(@SuppressWarnings("UnusedParameters") V value) throws Exception { }
277 }