1 package org.apache.lucene.util;
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 import java.io.Closeable;
21 import java.lang.ref.WeakReference;
22 import java.util.HashMap;
23 import java.util.Iterator;
26 /** Java's builtin ThreadLocal has a serious flaw:
27 * it can take an arbitrarily long amount of time to
28 * dereference the things you had stored in it, even once the
29 * ThreadLocal instance itself is no longer referenced.
30 * This is because there is single, master map stored for
31 * each thread, which all ThreadLocals share, and that
32 * master map only periodically purges "stale" entries.
34 * While not technically a memory leak, because eventually
35 * the memory will be reclaimed, it can take a long time
36 * and you can easily hit OutOfMemoryError because from the
37 * GC's standpoint the stale entries are not reclaimable.
39 * This class works around that, by only enrolling
40 * WeakReference values into the ThreadLocal, and
41 * separately holding a hard reference to each stored
42 * value. When you call {@link #close}, these hard
43 * references are cleared and then GC is freely able to
44 * reclaim space by objects stored in it.
46 * We can not rely on {@link ThreadLocal#remove()} as it
47 * only removes the value for the caller thread, whereas
48 * {@link #close} takes care of all
49 * threads. You should not call {@link #close} until all
50 * threads are done using the instance.
55 public class CloseableThreadLocal<T> implements Closeable {
57 private ThreadLocal<WeakReference<T>> t = new ThreadLocal<WeakReference<T>>();
59 private Map<Thread,T> hardRefs = new HashMap<Thread,T>();
61 protected T initialValue() {
66 WeakReference<T> weakRef = t.get();
67 if (weakRef == null) {
68 T iv = initialValue();
79 public void set(T object) {
81 t.set(new WeakReference<T>(object));
83 synchronized(hardRefs) {
84 hardRefs.put(Thread.currentThread(), object);
87 for (Iterator<Thread> it = hardRefs.keySet().iterator(); it.hasNext();) {
88 final Thread t = it.next();
96 // Clear the hard refs; then, the only remaining refs to
97 // all values we were storing are weak (unless somewhere
98 // else is still using them) and so GC may reclaim them:
100 // Take care of the current thread right now; others will be
101 // taken care of via the WeakReferences.