ThreadLocal.java revision f33eae7e84eb6d3b0f4e86b59605bb3de73009f3
1/*
2 * Copyright (C) 2008 The Android Open Source Project
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
17package java.lang;
18
19/*
20 * Android's thread local is not derived from Harmony's classlib. It is used in
21 * Harmony's DRLVM, however, whose source is here:
22 * http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/
23 */
24
25import java.lang.ref.WeakReference;
26import java.lang.ref.Reference;
27import java.util.concurrent.atomic.AtomicInteger;
28
29/**
30 * Implements a thread-local storage, that is, a variable for which each thread
31 * has its own value. All threads share the same {@code ThreadLocal} object,
32 * but each sees a different value when accessing it, and changes made by one
33 * thread do not affect the other threads. The implementation supports
34 * {@code null} values.
35 *
36 * @see java.lang.Thread
37 * @author Bob Lee
38 */
39public class ThreadLocal<T> {
40
41    /* Thanks to Josh Bloch and Doug Lea for code reviews and impl advice. */
42
43    /**
44     * Creates a new thread-local variable.
45     */
46    public ThreadLocal() {}
47
48    /**
49     * Returns the value of this variable for the current thread. If an entry
50     * doesn't yet exist for this variable on this thread, this method will
51     * create an entry, populating the value with the result of
52     * {@link #initialValue()}.
53     *
54     * @return the current value of the variable for the calling thread.
55     */
56    @SuppressWarnings("unchecked")
57    public T get() {
58        // Optimized for the fast path.
59        Thread currentThread = Thread.currentThread();
60        Values values = values(currentThread);
61        if (values != null) {
62            Object[] table = values.table;
63            int index = hash & values.mask;
64            if (this.reference == table[index]) {
65                return (T) table[index + 1];
66            }
67        } else {
68            values = initializeValues(currentThread);
69        }
70
71        return (T) values.getAfterMiss(this);
72    }
73
74    /**
75     * Provides the initial value of this variable for the current thread.
76     * The default implementation returns {@code null}.
77     *
78     * @return the initial value of the variable.
79     */
80    protected T initialValue() {
81        return null;
82    }
83
84    /**
85     * Sets the value of this variable for the current thread. If set to
86     * {@code null}, the value will be set to null and the underlying entry will
87     * still be present.
88     *
89     * @param value the new value of the variable for the caller thread.
90     */
91    public void set(T value) {
92        Thread currentThread = Thread.currentThread();
93        Values values = values(currentThread);
94        if (values == null) {
95            values = initializeValues(currentThread);
96        }
97        values.put(this, value);
98    }
99
100    /**
101     * Removes the entry for this variable in the current thread. If this call
102     * is followed by a {@link #get()} before a {@link #set},
103     * {@code #get()} will call {@link #initialValue()} and create a new
104     * entry with the resulting value.
105     *
106     * @since 1.5
107     */
108    public void remove() {
109        Thread currentThread = Thread.currentThread();
110        Values values = values(currentThread);
111        if (values != null) {
112            values.remove(this);
113        }
114    }
115
116    /**
117     * Creates Values instance for this thread and variable type.
118     */
119    Values initializeValues(Thread current) {
120        return current.localValues = new Values();
121    }
122
123    /**
124     * Gets Values instance for this thread and variable type.
125     */
126    Values values(Thread current) {
127        return current.localValues;
128    }
129
130    /** Weak reference to this thread local instance. */
131    private final Reference<ThreadLocal<T>> reference
132            = new WeakReference<ThreadLocal<T>>(this);
133
134    /** Hash counter. */
135    private static AtomicInteger hashCounter = new AtomicInteger(0);
136
137    /**
138     * Internal hash. We deliberately don't bother with #hashCode().
139     * Hashes must be even. This ensures that the result of
140     * (hash & (table.length - 1)) points to a key and not a value.
141     *
142     * We increment by Doug Lea's Magic Number(TM) (*2 since keys are in
143     * every other bucket) to help prevent clustering.
144     */
145    private final int hash = hashCounter.getAndAdd(0x61c88647 << 1);
146
147    /**
148     * Per-thread map of ThreadLocal instances to values.
149     */
150    static class Values {
151
152        /**
153         * Size must always be a power of 2.
154         */
155        private static final int INITIAL_SIZE = 16;
156
157        /**
158         * Placeholder for deleted entries.
159         */
160        private static final Object TOMBSTONE = new Object();
161
162        /**
163         * Map entries. Contains alternating keys (ThreadLocal) and values.
164         * The length is always a power of 2.
165         */
166        private Object[] table;
167
168        /** Used to turn hashes into indices. */
169        private int mask;
170
171        /** Number of live entries. */
172        private int size;
173
174        /** Number of tombstones. */
175        private int tombstones;
176
177        /** Maximum number of live entries and tombstones. */
178        private int maximumLoad;
179
180        /** Points to the next cell to clean up. */
181        private int clean;
182
183        /**
184         * Constructs a new, empty instance.
185         */
186        Values() {
187            initializeTable(INITIAL_SIZE);
188            this.size = 0;
189            this.tombstones = 0;
190        }
191
192        /**
193         * Used for InheritableThreadLocals.
194         */
195        Values(Values fromParent) {
196            this.table = fromParent.table.clone();
197            this.mask = fromParent.mask;
198            this.size = fromParent.size;
199            this.tombstones = fromParent.tombstones;
200            this.maximumLoad = fromParent.maximumLoad;
201            this.clean = fromParent.clean;
202            inheritValues(fromParent);
203        }
204
205        /**
206         * Inherits values from a parent thread.
207         */
208        @SuppressWarnings({"unchecked"})
209        private void inheritValues(Values fromParent) {
210            // Transfer values from parent to child thread.
211            Object[] table = this.table;
212            for (int i = table.length - 2; i >= 0; i -= 2) {
213                Object k = table[i];
214
215                if (k == null || k == TOMBSTONE) {
216                    // Skip this entry.
217                    continue;
218                }
219
220                // The table can only contain null, tombstones and references.
221                Reference<InheritableThreadLocal<?>> reference
222                        = (Reference<InheritableThreadLocal<?>>) k;
223                // Raw type enables us to pass in an Object below.
224                InheritableThreadLocal key = reference.get();
225                if (key != null) {
226                    // Replace value with filtered value.
227                    // We should just let exceptions bubble out and tank
228                    // the thread creation
229                    table[i + 1] = key.childValue(fromParent.table[i + 1]);
230                } else {
231                    // The key was reclaimed.
232                    table[i] = TOMBSTONE;
233                    table[i + 1] = null;
234                    fromParent.table[i] = TOMBSTONE;
235                    fromParent.table[i + 1] = null;
236
237                    tombstones++;
238                    fromParent.tombstones++;
239
240                    size--;
241                    fromParent.size--;
242                }
243            }
244        }
245
246        /**
247         * Creates a new, empty table with the given capacity.
248         */
249        private void initializeTable(int capacity) {
250            this.table = new Object[capacity << 1];
251            this.mask = table.length - 1;
252            this.clean = 0;
253            this.maximumLoad = capacity * 2 / 3; // 2/3
254        }
255
256        /**
257         * Cleans up after garbage-collected thread locals.
258         */
259        private void cleanUp() {
260            if (rehash()) {
261                // If we rehashed, we needn't clean up (clean up happens as
262                // a side effect).
263                return;
264            }
265
266            if (size == 0) {
267                // No live entries == nothing to clean.
268                return;
269            }
270
271            // Clean log(table.length) entries picking up where we left off
272            // last time.
273            int index = clean;
274            Object[] table = this.table;
275            for (int counter = table.length; counter > 0; counter >>= 1,
276                    index = next(index)) {
277                Object k = table[index];
278
279                if (k == TOMBSTONE || k == null) {
280                    continue; // on to next entry
281                }
282
283                // The table can only contain null, tombstones and references.
284                @SuppressWarnings("unchecked")
285                Reference<ThreadLocal<?>> reference
286                        = (Reference<ThreadLocal<?>>) k;
287                if (reference.get() == null) {
288                    // This thread local was reclaimed by the garbage collector.
289                    table[index] = TOMBSTONE;
290                    table[index + 1] = null;
291                    tombstones++;
292                    size--;
293                }
294            }
295
296            // Point cursor to next index.
297            clean = index;
298        }
299
300        /**
301         * Rehashes the table, expanding or contracting it as necessary.
302         * Gets rid of tombstones. Returns true if a rehash occurred.
303         * We must rehash every time we fill a null slot; we depend on the
304         * presence of null slots to end searches (otherwise, we'll infinitely
305         * loop).
306         */
307        private boolean rehash() {
308            if (tombstones + size < maximumLoad) {
309                return false;
310            }
311
312            int capacity = table.length >> 1;
313
314            // Default to the same capacity. This will create a table of the
315            // same size and move over the live entries, analogous to a
316            // garbage collection. This should only happen if you churn a
317            // bunch of thread local garbage (removing and reinserting
318            // the same thread locals over and over will overwrite tombstones
319            // and not fill up the table).
320            int newCapacity = capacity;
321
322            if (size > (capacity >> 1)) {
323                // More than 1/2 filled w/ live entries.
324                // Double size.
325                newCapacity = capacity << 1;
326            }
327
328            Object[] oldTable = this.table;
329
330            // Allocate new table.
331            initializeTable(newCapacity);
332
333            // We won't have any tombstones after this.
334            this.tombstones = 0;
335
336            // If we have no live entries, we can quit here.
337            if (size == 0) {
338                return true;
339            }
340
341            // Move over entries.
342            for (int i = oldTable.length - 2; i >= 0; i -= 2) {
343                Object k = oldTable[i];
344                if (k == null || k == TOMBSTONE) {
345                    // Skip this entry.
346                    continue;
347                }
348
349                // The table can only contain null, tombstones and references.
350                @SuppressWarnings("unchecked")
351                Reference<ThreadLocal<?>> reference
352                        = (Reference<ThreadLocal<?>>) k;
353                ThreadLocal<?> key = reference.get();
354                if (key != null) {
355                    // Entry is still live. Move it over.
356                    add(key, oldTable[i + 1]);
357                } else {
358                    // The key was reclaimed.
359                    size--;
360                }
361            }
362
363            return true;
364        }
365
366        /**
367         * Adds an entry during rehashing. Compared to put(), this method
368         * doesn't have to clean up, check for existing entries, account for
369         * tombstones, etc.
370         */
371        void add(ThreadLocal<?> key, Object value) {
372            for (int index = key.hash & mask;; index = next(index)) {
373                Object k = table[index];
374                if (k == null) {
375                    table[index] = key.reference;
376                    table[index + 1] = value;
377                    return;
378                }
379            }
380        }
381
382        /**
383         * Sets entry for given ThreadLocal to given value, creating an
384         * entry if necessary.
385         */
386        void put(ThreadLocal<?> key, Object value) {
387            cleanUp();
388
389            // Keep track of first tombstone. That's where we want to go back
390            // and add an entry if necessary.
391            int firstTombstone = -1;
392
393            for (int index = key.hash & mask;; index = next(index)) {
394                Object k = table[index];
395
396                if (k == key.reference) {
397                    // Replace existing entry.
398                    table[index + 1] = value;
399                    return;
400                }
401
402                if (k == null) {
403                    if (firstTombstone == -1) {
404                        // Fill in null slot.
405                        table[index] = key.reference;
406                        table[index + 1] = value;
407                        size++;
408                        return;
409                    }
410
411                    // Go back and replace first tombstone.
412                    table[firstTombstone] = key.reference;
413                    table[firstTombstone + 1] = value;
414                    tombstones--;
415                    size++;
416                    return;
417                }
418
419                // Remember first tombstone.
420                if (firstTombstone == -1 && k == TOMBSTONE) {
421                    firstTombstone = index;
422                }
423            }
424        }
425
426        /**
427         * Gets value for given ThreadLocal after not finding it in the first
428         * slot.
429         */
430        Object getAfterMiss(ThreadLocal<?> key) {
431            Object[] table = this.table;
432            int index = key.hash & mask;
433
434            // If the first slot is empty, the search is over.
435            if (table[index] == null) {
436                Object value = key.initialValue();
437
438                // If the table is still the same and the slot is still empty...
439                if (this.table == table && table[index] == null) {
440                    table[index] = key.reference;
441                    table[index + 1] = value;
442                    size++;
443
444                    cleanUp();
445                    return value;
446                }
447
448                // The table changed during initialValue().
449                put(key, value);
450                return value;
451            }
452
453            // Keep track of first tombstone. That's where we want to go back
454            // and add an entry if necessary.
455            int firstTombstone = -1;
456
457            // Continue search.
458            for (index = next(index);; index = next(index)) {
459                Object reference = table[index];
460                if (reference == key.reference) {
461                    return table[index + 1];
462                }
463
464                // If no entry was found...
465                if (reference == null) {
466                    Object value = key.initialValue();
467
468                    // If the table is still the same...
469                    if (this.table == table) {
470                        // If we passed a tombstone and that slot still
471                        // contains a tombstone...
472                        if (firstTombstone > -1
473                                && table[firstTombstone] == TOMBSTONE) {
474                            table[firstTombstone] = key.reference;
475                            table[firstTombstone + 1] = value;
476                            tombstones--;
477                            size++;
478
479                            // No need to clean up here. We aren't filling
480                            // in a null slot.
481                            return value;
482                        }
483
484                        // If this slot is still empty...
485                        if (table[index] == null) {
486                            table[index] = key.reference;
487                            table[index + 1] = value;
488                            size++;
489
490                            cleanUp();
491                            return value;
492                        }
493                    }
494
495                    // The table changed during initialValue().
496                    put(key, value);
497                    return value;
498                }
499
500                if (firstTombstone == -1 && reference == TOMBSTONE) {
501                    // Keep track of this tombstone so we can overwrite it.
502                    firstTombstone = index;
503                }
504            }
505        }
506
507        /**
508         * Removes entry for the given ThreadLocal.
509         */
510        void remove(ThreadLocal<?> key) {
511            cleanUp();
512
513            for (int index = key.hash & mask;; index = next(index)) {
514                Object reference = table[index];
515
516                if (reference == key.reference) {
517                    // Success!
518                    table[index] = TOMBSTONE;
519                    table[index + 1] = null;
520                    tombstones++;
521                    size--;
522                    return;
523                }
524
525                if (reference == null) {
526                    // No entry found.
527                    return;
528                }
529            }
530        }
531
532        /**
533         * Gets the next index. If we're at the end of the table, we wrap back
534         * around to 0.
535         */
536        private int next(int index) {
537            return (index + 2) & mask;
538        }
539    }
540}
541