001
014
015 package com.liferay.portal.kernel.util;
016
017 import java.util.HashMap;
018 import java.util.Map;
019 import java.util.concurrent.atomic.AtomicInteger;
020
021
024 public class CentralizedThreadLocal<T> extends ThreadLocal<T> {
025
026 public static void clearLongLivedThreadLocals() {
027 _longLivedThreadLocals.remove();
028 }
029
030 public static void clearShortLivedThreadLocals() {
031 _shortLivedThreadLocals.remove();
032 }
033
034 public static Map<CentralizedThreadLocal<?>, Object>
035 getLongLivedThreadLocals() {
036
037 return _toMap(_longLivedThreadLocals.get());
038 }
039
040 public static Map<CentralizedThreadLocal<?>, Object>
041 getShortLivedThreadLocals() {
042
043 return _toMap(_shortLivedThreadLocals.get());
044 }
045
046 public static void setThreadLocals(
047 Map<CentralizedThreadLocal<?>, Object> longLivedThreadLocals,
048 Map<CentralizedThreadLocal<?>, Object> shortLivedThreadLocals) {
049
050 ThreadLocalMap threadLocalMap = _longLivedThreadLocals.get();
051
052 for (Map.Entry<CentralizedThreadLocal<?>, Object> entry :
053 longLivedThreadLocals.entrySet()) {
054
055 threadLocalMap.putEntry(entry.getKey(), entry.getValue());
056 }
057
058 threadLocalMap = _shortLivedThreadLocals.get();
059
060 for (Map.Entry<CentralizedThreadLocal<?>, Object> entry :
061 shortLivedThreadLocals.entrySet()) {
062
063 threadLocalMap.putEntry(entry.getKey(), entry.getValue());
064 }
065 }
066
067 public CentralizedThreadLocal(boolean shortLived) {
068 _shortLived = shortLived;
069
070 if (shortLived) {
071 _hashCode = _shortLivedNextHasCode.getAndAdd(_HASH_INCREMENT);
072 }
073 else {
074 _hashCode = _longLivedNextHasCode.getAndAdd(_HASH_INCREMENT);
075 }
076 }
077
078 @Override
079 public T get() {
080 ThreadLocalMap threadLocalMap = _getThreadLocalMap();
081
082 Entry entry = threadLocalMap.getEntry(this);
083
084 if (entry == null) {
085 T value = initialValue();
086
087 threadLocalMap.putEntry(this, value);
088
089 return value;
090 }
091 else {
092 return (T)entry._value;
093 }
094 }
095
096 @Override
097 public int hashCode() {
098 return _hashCode;
099 }
100
101 @Override
102 public void remove() {
103 ThreadLocalMap threadLocalMap = _getThreadLocalMap();
104
105 threadLocalMap.removeEntry(this);
106 }
107
108 @Override
109 public void set(T value) {
110 ThreadLocalMap threadLocalMap = _getThreadLocalMap();
111
112 threadLocalMap.putEntry(this, value);
113 }
114
115 private static Map<CentralizedThreadLocal<?>, Object> _toMap(
116 ThreadLocalMap threadLocalMap) {
117
118 Map<CentralizedThreadLocal<?>, Object> map =
119 new HashMap<CentralizedThreadLocal<?>, Object>(
120 threadLocalMap._table.length);
121
122 for (Entry entry : threadLocalMap._table) {
123 map.put(entry._key, entry._value);
124 }
125
126 return map;
127 }
128
129 private ThreadLocalMap _getThreadLocalMap() {
130 if (_shortLived) {
131 return _shortLivedThreadLocals.get();
132 }
133 else {
134 return _longLivedThreadLocals.get();
135 }
136 }
137
138 private static final int _HASH_INCREMENT = 0x61c88647;
139
140 private static final AtomicInteger _longLivedNextHasCode =
141 new AtomicInteger();
142 private static final ThreadLocal<ThreadLocalMap> _longLivedThreadLocals =
143 new ThreadLocalMapThreadLocal();
144 private static final AtomicInteger _shortLivedNextHasCode =
145 new AtomicInteger();
146 private static final ThreadLocal<ThreadLocalMap> _shortLivedThreadLocals =
147 new ThreadLocalMapThreadLocal();
148
149 private final int _hashCode;
150 private final boolean _shortLived;
151
152 private static class Entry {
153
154 public Entry(CentralizedThreadLocal<?> key, Object value, Entry next) {
155 _key = key;
156 _value = value;
157 _next = next;
158 }
159
160 private CentralizedThreadLocal<?> _key;
161 private Entry _next;
162 private Object _value;
163
164 }
165
166 private static class ThreadLocalMap {
167
168 public void expand(int newCapacity) {
169 if (_table.length == _MAXIMUM_CAPACITY) {
170 _threshold = Integer.MAX_VALUE;
171
172 return;
173 }
174
175 Entry[] newTable = new Entry[newCapacity];
176
177 for (int i = 0; i < _table.length; i++) {
178 Entry entry = _table[i];
179
180 if (entry == null) {
181 continue;
182 }
183
184 _table[i] = null;
185
186 do {
187 Entry nextEntry = entry._next;
188
189 int index = entry._key._hashCode & (newCapacity - 1);
190
191 entry._next = newTable[index];
192
193 newTable[index] = entry;
194
195 entry = nextEntry;
196 }
197 while (entry != null);
198 }
199
200 _table = newTable;
201
202 _threshold = newCapacity * 2 / 3;
203 }
204
205 public Entry getEntry(CentralizedThreadLocal<?> key) {
206 int index = key._hashCode & (_table.length - 1);
207
208 Entry entry = _table[index];
209
210 if (entry == null) {
211 return null;
212 }
213 else if (entry._key == key) {
214 return entry;
215 }
216 else {
217 while ((entry = entry._next) != null) {
218 if (entry._key == key) {
219 return entry;
220 }
221 }
222
223 return null;
224 }
225 }
226
227 public void putEntry(CentralizedThreadLocal<?> key, Object value) {
228 int index = key._hashCode & (_table.length - 1);
229
230 for (Entry entry = _table[index]; entry != null;
231 entry = entry._next) {
232
233 if (entry._key == key) {
234 entry._value = value;
235
236 return;
237 }
238 }
239
240 _table[index] = new Entry(key, value, _table[index]);
241
242 if (_size++ >= _threshold) {
243 expand(2 * _table.length);
244 }
245 }
246
247 public void removeEntry(CentralizedThreadLocal<?> key) {
248 int index = key._hashCode & (_table.length - 1);
249
250 Entry previousEntry = null;
251
252 Entry entry = _table[index];
253
254 while (entry != null) {
255 Entry nextEntry = entry._next;
256
257 if (entry._key == key) {
258 _size--;
259
260 if (previousEntry == null) {
261 _table[index] = nextEntry;
262 }
263 else {
264 previousEntry._next = nextEntry;
265 }
266
267 return;
268 }
269
270 previousEntry = entry;
271 entry = nextEntry;
272 }
273 };
274
275 private static final int _INITIAL_CAPACITY = 16;
276
277 private static final int _MAXIMUM_CAPACITY = 1 << 30;
278
279 private int _size;
280 private Entry[] _table = new Entry[_INITIAL_CAPACITY];
281 private int _threshold = _INITIAL_CAPACITY * 2 / 3;
282
283 }
284
285 private static class ThreadLocalMapThreadLocal
286 extends ThreadLocal<ThreadLocalMap> {
287
288 @Override
289 protected ThreadLocalMap initialValue() {
290 return new ThreadLocalMap();
291 }
292
293 }
294
295 }