Just a few examples of "problems" using ThreadLocals.
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2481
http://www.theserverside.com/news/thread.tss?thread_id=41473
Once again, I'm not pointing to Lucene SegmentReader as a "bad"
implementation, and maybe the current "problems" of ThreadLocals are not
a problem for SegmentReader but it seems safer to use ThreadLocals to
pass context information which is cleared when the call exits instead of
storing long-lived objects.
robert engels wrote:
> Aside from the pre-1.5 thread local "perceived leak", there are no
> issues with ThreadLocals if used properly.
>
> There is no need for try/finally blocks, unless you MUST release
> resources immediately, usually this is not the case, which is why a
> ThreadLocal is used in the first place.
>
> From the ThreadLocalMap javadoc...
>
> /**
> * ThreadLocalMap is a customized hash map suitable only for
> * maintaining thread local values. No operations are exported
> * outside of the ThreadLocal class. The class is package private to
> * allow declaration of fields in class Thread. To help deal with
> * very large and long-lived usages, the hash table entries use
> * WeakReferences for keys. However, since reference queues are not
> * used, stale entries are guaranteed to be removed only when
> * the table starts running out of space.
> */
>
> /**
> * Heuristically scan some cells looking for stale entries.
> * This is invoked when either a new element is added, or
> * another stale one has been expunged. It performs a
> * logarithmic number of scans, as a balance between no
> * scanning (fast but retains garbage) and a number of scans
> * proportional to number of elements, that would find all
> * garbage but would cause some insertions to take O(n) time.
> *
> * @param i a position known NOT to hold a stale entry. The
> * scan starts at the element after i.
> *
> * @param n scan control: log2(n) cells are scanned,
> * unless a stale entry one is found, in which case
> * log2(table.length)-1 additional cells are scanned.
> * When called from insertions, this parameter is the number
> * of elements, but when from replaceStaleEntry, it is the
> * table length. (Note: all this could be changed to be either
> * more or less aggressive by weighting n instead of just
> * using straight log n. But this version is simple, fast, and
> * seems to work well.)
> *
> * @return true if any stale entries have been removed.
> */
>
>
> The instance ThreadLocals (and what the refer to) will be GC'd when
> the containing Object is GC'd.
>
> There IS NO MEMORY LEAK in ThreadLocal. If the ThreadLocal refers to
> an object that has native resources (e.g. file handles), it may not be
> released until other thread locals are created by the thread (or the
> thread terminates).
>
> You can avoid this "delay" by calling remove(), but in most
> applications it should never be necessary - unless a very strange usage...
>
> On Jul 9, 2008, at 2:37 PM, Adrian Tarau wrote:
>
>> From what I know, storing objects in ThreadLocal is safe as long as
>> you release the object within a try {} finall {} block or store
>> objects which are independent of the rest of the code(no
>> dependencies).Otherwise it can get pretty tricky(memory leaks,
>> classloader problems) after awhile.
>>
>> It is pretty convenient to pass HTTP request information with a
>> ThreadLocal in a servlet(but you should cleanup the variable before
>> leaving the servlet) but I'm not sure how safe it is in this case.
>>
>> robert engels wrote:
>>> Using synchronization is a poor/invalid substitute for thread locals
>>> in many cases.
>>>
>>> The point of the thread local in these referenced cases is too allow
>>> streaming reads on a file descriptor. if you use a shared file
>>> descriptor/buffer you are going to continually invalidate the buffer.
>>>
>>> On Jul 8, 2008, at 5:12 AM, Michael McCandless wrote:
>>>
>>>>
>>>> Well ... SegmentReader uses ThreadLocal to hold a thread-private
>>>> instance of TermVectorsReader, to avoid synchronizing per-document
>>>> when loading term vectors.
>>>>
>>>> Clearing this ThreadLocal value per call to SegmentReader's methods
>>>> that load term vectors would defeat its purpose.
>>>>
>>>> Though, of course, we then synchronize on the underlying file (when
>>>> using FSDirectory), so perhaps we are really not saving much by
>>>> using ThreadLocal here. But we are looking to relax that low level
>>>> synchronization with LUCENE-753.
>>>>
>>>> Maybe we could make our own ThreadLocal that just uses a HashMap,
>>>> which we'd have to synchronize on when getting the per-thread
>>>> instances. Or, go back to sharing a single TermVectorsReader and
>>>> synchronize per-document.
>>>>
>>>> Jason has suggested moving to a model where you ask the IndexReader
>>>> for an object that can return term vectors / stored fields / etc,
>>>> and then you interact with that many times to retrieve each doc.
>>>> We could then synchronize only on retrieving that object, and
>>>> provide a thread-private instance.
>>>>
>>>> It seems like we should move away from using ThreadLocal in Lucene
>>>> and do "normal" synchronization instead.
>>>>
>>>> Mike
>>>>
>>>> Adrian Tarau wrote:
>>>>
>>>>> Usually ThreadLocal.remove() should be called at the end(in a
>>>>> finally block), before the current call leaves your code.
>>>>>
>>>>> Ex : if during searching ThreadLocal is used, every search(..)
>>>>> method should cleanup any ThreadLocal variables, or even deeper in
>>>>> the implementation. When the call leaves Lucene any used
>>>>> ThreadLocal should be cleaned up.
>>>>>
>>>>> Michael McCandless wrote:
>>>>>>
>>>>>> ThreadLocal, which we use in several places in Lucene, causes a
>>>>>> leak in app servers because the classloader never fully
>>>>>> deallocates Lucene's classes because the ThreadLocal is holding
>>>>>> strong references.
>>>>>>
>>>>>> Yet, ThreadLocal is very convenient for avoiding synchronization.
>>>>>>
>>>>>> Does anyone have any ideas on how to solve this w/o falling back
>>>>>> to "normal" synchronization?
>>>>>>
>>>>>> Mike
>>>>>>
>>>>>> Begin forwarded message:
>>>>>>
>>>>>>> From: "Yonik Seeley" >
>>>>>>> Date: July 7, 2008 3:30:28 PM EDT
>>>>>>> To: java-user@lucene.apache.org
>>>>>>> Subject: Re: ThreadLocal in SegmentReader
>>>>>>> Reply-To: java-user@lucene.apache.org
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Jul 7, 2008 at 2:43 PM, Michael McCandless
>>>>>>> >
>>>>>>> wrote:
>>>>>>>> So now I'm confused: the SegmentReader itself should no longer
>>>>>>>> be reachable,
>>>>>>>> assuming you are not holding any references to your IndexReader.
>>>>>>>>
>>>>>>>> Which means the ThreadLocal instance should no longer be reachable.
>>>>>>>
>>>>>>> It will still be referenced from the Thread(s) ThreadLocalMap
>>>>>>> The key (the ThreadLocal) will be weakly referenced, but the values
>>>>>>> (now stale) are strongly referenced and won't be actually removed
>>>>>>> until the table is resized (under the Java6 impl at least).
>>>>>>> Nice huh?
>>>>>>>
>>>>>>> -Yonik
>>>>>>>
>>>>>>> ---------------------------------------------------------------------
>>>>>>> To unsubscribe, e-mail: java-user-unsubscribe@lucene.apache.org
>>>>>>>
>>>>>>> For additional commands, e-mail:
>>>>>>> java-user-help@lucene.apache.org
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: java-dev-unsubscribe@lucene.apache.org
>>>>>>
>>>>>> For additional commands, e-mail: java-dev-help@lucene.apache.org
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: java-dev-unsubscribe@lucene.apache.org
>>>>>
>>>>> For additional commands, e-mail: java-dev-help@lucene.apache.org
>>>>>
>>>>>
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: java-dev-unsubscribe@lucene.apache.org
>>>>
>>>> For additional commands, e-mail: java-dev-help@lucene.apache.org
>>>>
>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: java-dev-unsubscribe@lucene.apache.org
>>>
>>> For additional commands, e-mail: java-dev-help@lucene.apache.org
>>>
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: java-dev-unsubscribe@lucene.apache.org
>>
>> For additional commands, e-mail: java-dev-help@lucene.apache.org
>>
>>
>