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&lt;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