pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / java / org / apache / lucene / util / CloseableThreadLocal.java
1 package org.apache.lucene.util;
2
3 /**
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
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  */
19
20 import java.io.Closeable;
21 import java.lang.ref.WeakReference;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25
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.
33  *
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.
38  * 
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.
45  *
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.
51  *
52  * @lucene.internal
53  */
54
55 public class CloseableThreadLocal<T> implements Closeable {
56
57   private ThreadLocal<WeakReference<T>> t = new ThreadLocal<WeakReference<T>>();
58
59   private Map<Thread,T> hardRefs = new HashMap<Thread,T>();
60   
61   protected T initialValue() {
62     return null;
63   }
64   
65   public T get() {
66     WeakReference<T> weakRef = t.get();
67     if (weakRef == null) {
68       T iv = initialValue();
69       if (iv != null) {
70         set(iv);
71         return iv;
72       } else
73         return null;
74     } else {
75       return weakRef.get();
76     }
77   }
78
79   public void set(T object) {
80
81     t.set(new WeakReference<T>(object));
82
83     synchronized(hardRefs) {
84       hardRefs.put(Thread.currentThread(), object);
85
86       // Purge dead threads
87       for (Iterator<Thread> it = hardRefs.keySet().iterator(); it.hasNext();) {
88         final Thread t = it.next();
89         if (!t.isAlive())
90           it.remove();
91       }
92     }
93   }
94
95   public void close() {
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:
99     hardRefs = null;
100     // Take care of the current thread right now; others will be
101     // taken care of via the WeakReferences.
102     if (t != null) {
103       t.remove();
104     }
105     t = null;
106   }
107 }