[concurrency-interest] Soliciting input about removeAllThreadLocals

Vijay Saraswat vijay@saraswat.org
Sat, 07 Dec 2002 06:09:23 -0500


Dear Doug and others --

Here is a "use case". On a project that I was involved with (for 
providing a servlet-based service -- it doesnt matter what the service 
is), we used log4j for logging. Various format statements needed access 
to the current "session" object (which had user information etc -- this 
needed to be printed out in the logs). So we associated various 
threadlocal variables with the Thread. This association is made 
uniformly in doGet before application specific code is invoked. A 
"finally" around the code invoking the app code took care to reset the 
thread local state.

Having the underlying ThreadPool implementation for the servlet runner 
use a removeAllThreadLocals would not break this pattern.

On the other hand, I can clearly see the need for the ability to 
establish different ThreadLocal state with different extent. For 
instance, it may be necessary to associate a Thread with state (e.g. a 
capability to perform certain actions, e.g. access to a DB or some 
external server) that is accessible across repeated uses of the Thread 
within an executor. Therefore if the ThreadPool which has been given 
this Thread tries to removeAllThreadLocals -- that would not be good. In 
other words, there are legitimate reasons for keeping some state on a 
Thread whose extent spans the use of the Thread to service a particular 
task.

My advice would be to strongly encourage users to use a pattern that 
sets the ThreadLocals to be used by this piece of code at the very 
beginning of the task (to be run by the Executor) , which then invokes 
the rest of the code wrapped in a finally which cleans up the 
ThreadLocal storage (for instance setting the ThreadLocal variable to null).

I dont like the way ThreadLocal works in Java -- this is a place where 
the type system should help out. Needs a redesign :-(.

Best,
Vijay


Doug Lea wrote:

>Dear concurrency-interest list members,
>
>We in the expert group have been periodically arguing about the
>proposed Thread.removeAllThreadLocals method.  This method erases ALL
>of the ThreadLocals associated with a thread, so that the next time
>access of any of them is attempted, its initialValue() is returned.
>
>The main issues are:
>
> *  Supporting removeAllThreadLocals provides an (optional) way to
>    prevent tasks run by worker Threads in Executors (i.e., mainly,
>    ThreadExecutor) from using "leftover" values of ThreadLocals from
>    previous tasks, which will likely be the source of subtle bugs.
>    Normal use here would be to call removeAllThreadLocals in one or
>    more ExecutorIntercepts methods when you'd like to prevent such
>    problems. This way, each task runs under a worker thread just like
>    it would under a new Thread, except that the thread is actually
>    the same one as used for a previous task.
>
> *  But having such a method is otherwise a potential breach of
>    encapsulation, and could cause problems with other
>    classes/componentss expecting their ThreadLocals to forever be
>    associated with threads, even worker threads that perform many
>    unrelated tasks.
>
>The question is, which is worse, 
>  (1) unexpected reuse, 
>or 
>  (2) unexpected clearing. 
>
>Specifically, is (2) such a serious problem that removeAllThreadLocals
>shouldn't be supported, forcing people to live with (1), or to not use
>ThreadExecutors when this problem arises?
>
>To alleviate (2), if we keep the capacity for removing all
>ThreadLocals, we will probably restructure things with the net effect
>that this can be done only for worker threads within Executors, not
>for arbitrary Threads.
>
>Note that if you know of a particular problematic ThreadLocal, you can
>always either invoke ThreadLocal.set(null) or better, the new
>ThreadLocal.remove() method on it to clear it from within executor
>intercepts. The removeAllThreadLocals method differs here in that it
>also clears those ThreadLocals that the Executor does not otherwise
>know about.
>
>We'd like to collect experiences about this. (Not opinions -- we have
>equally strong "over my dead body" views on each side of this already
>in the expert group!).  If you are currently using some kind of thread
>pool (perhaps dl.u.c.PooledExecutor), and/or programs that make heavy
>use of ThreadLocals, please tell us if:
>
>   * You have encountered problems due to leftover ThreadLocals
>     spilling over across tasks performed by the same thread.
>Or
>
>   * You have code that would break if run via ThreadExecutors that
>     cleared all ThreadLocals between tasks.
>
>Or related horror stories surrounding ThreadLocals.
>
>Thanks very much!
>
>  
>