1 /**
2 * Copyright 2006 Thomas Hawtin
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.ehcache.util.lang;
17
18 import java.lang.ref.ReferenceQueue;
19 import java.lang.ref.WeakReference;
20 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
21
22 /**
23 * A drop-in replacement {@code ThreadLocal} implementation that does not leak
24 * when thread-local values reference the {@code ThreadLocal} object.
25 * The code is optimised to cope with frequently changing values.
26 * <p/>
27 * In comparison to plain {@code ThreadLocal}, this implementation:<ul>
28 * <li>from the point of view of a single thread,
29 * each thread-local
30 * {code #get} requires access to four objects instead of two
31 * <li>is fractionally slower in terms of CPU cycles for {code #get}
32 * <li>uses around twice the memory for each thead-local value
33 * <li>uses around four times the memory for each {@code ThreadLocal}
34 * <li>may release thread-local values for garbage collection more promptly
35 * </ul>
36 */
37 public class VicariousThreadLocal<T> extends ThreadLocal<T> {
38 /**
39 * Maps a unique WeakReference onto each Thread.
40 */
41 private static final ThreadLocal<WeakReference<Thread>> weakThread =
42 new ThreadLocal<WeakReference<Thread>>();
43
44 /**
45 * Returns a unique object representing the current thread.
46 * Although we use a weak-reference to the thread,
47 * we could use practically anything
48 * that does not reference our class-loader.
49 */
50 static WeakReference<Thread> currentThreadRef() {
51 WeakReference<Thread> ref = weakThread.get();
52 if (ref == null) {
53 ref = new WeakReference<Thread>(Thread.currentThread());
54 weakThread.set(ref);
55 }
56 return ref;
57 }
58
59 /**
60 * Object representing an uninitialised value.
61 */
62 private static final Object UNINITIALISED = new Object();
63
64 /**
65 * Actual ThreadLocal implementation object.
66 */
67 private final ThreadLocal<WeakReference<Holder>> local =
68 new ThreadLocal<WeakReference<Holder>>();
69
70 /**
71 * Maintains a strong reference to value for each thread,
72 * so long as the Thread has not been collected.
73 * Note, alive Threads strongly references the WeakReference<Thread>
74 * through weakThread.
75 */
76 private volatile Holder strongRefs;
77
78 /**
79 * Compare-and-set of {@link #strongRefs}.
80 */
81 private static final AtomicReferenceFieldUpdater<VicariousThreadLocal, Holder> strongRefsUpdater =
82 AtomicReferenceFieldUpdater.newUpdater(VicariousThreadLocal.class, Holder.class, "strongRefs");
83
84 /**
85 * Queue of Holders belonging to exited threads.
86 */
87 private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
88
89 /**
90 * Creates a new {@code VicariousThreadLocal}.
91 */
92 public VicariousThreadLocal() {
93 //
94 }
95
96 @SuppressWarnings("unchecked")
97 @Override
98 public T get() {
99 final Holder holder;
100 WeakReference<Holder> ref = local.get();
101 if (ref != null) {
102 holder = ref.get();
103 Object value = holder.value;
104 if (value != UNINITIALISED) {
105 return (T)value;
106 }
107 } else {
108 holder = createHolder();
109 }
110 T value = initialValue();
111 holder.value = value;
112 return value;
113 }
114
115 @Override
116 public void set(T value) {
117 WeakReference<Holder> ref = local.get();
118 final Holder holder =
119 ref != null ? ref.get() : createHolder();
120 holder.value = value;
121 }
122
123 /**
124 * Creates a new holder object, and registers it appropriately.
125 * Also polls for thread-exits.
126 */
127 private Holder createHolder() {
128 poll();
129 Holder holder = new Holder(queue);
130 WeakReference<Holder> ref = new WeakReference<Holder>(holder);
131
132 Holder old;
133 do {
134 old = strongRefs;
135 holder.next = old;
136 } while (!strongRefsUpdater.compareAndSet(this, old, holder));
137
138 local.set(ref);
139 return holder;
140 }
141
142 @Override
143 public void remove() {
144 WeakReference<Holder> ref = local.get();
145 if (ref != null) {
146 ref.get().value = UNINITIALISED;
147 }
148 }
149
150 /**
151 * Check if any strong references need should be removed due to thread exit.
152 */
153 public void poll() {
154 synchronized (queue) {
155 // Remove queued references.
156 // (Is this better inside or out?)
157 if (queue.poll() == null) {
158 // Nothing to do.
159 return;
160 }
161 while (queue.poll() != null) {
162 // Discard.
163 }
164
165 // Remove any dead holders.
166 Holder first = strongRefs;
167 if (first == null) {
168 // Unlikely...
169 return;
170 }
171 Holder link = first;
172 Holder next = link.next;
173 while (next != null) {
174 if (next.get() == null) {
175 next = next.next;
176 link.next = next;
177 } else {
178 link = next;
179 next = next.next;
180 }
181 }
182
183 // Remove dead head, possibly.
184 if (first.get() == null) {
185 if (!strongRefsUpdater.weakCompareAndSet(
186 this, first, first.next
187 )) {
188 // Something else has come along.
189 // Just null out - next search will remove it.
190 first.value = null;
191 }
192 }
193 }
194 }
195
196 /**
197 * Holds strong reference to a thread-local value.
198 * The WeakReference is to a thread-local representing the current thread.
199 */
200 private static class Holder extends WeakReference<Object> {
201 /**
202 * Construct a new holder for the current thread.
203 */
204 Holder(ReferenceQueue<Object> queue) {
205 super(currentThreadRef(), queue);
206 }
207
208 /**
209 * Next holder in chain for this thread-local.
210 */
211 Holder next;
212 /**
213 * Current thread-local value.
214 * {@link #UNINITIALISED} represents an uninitialised value.
215 */
216 Object value = UNINITIALISED;
217 }
218 }
219