views:

225

answers:

1

Hi I have class definition like this

public class JdbcInterceptor {
private static final JdbcInterceptor instance = new JdbcInterceptor();
private static ThreadLocal<Boolean> dontIntercept = new ThreadLocal<Boolean>();
     public static JdbcInterceptor getInstance() {
 return instance;
}
public void skipIntercept() {
 dontIntercept.set(true);
}
public boolean interrupt() {
boolean di = dontIntercept.get()!=null?dontIntercept.get().booleanValue():false;
if (di) {
        dontIntercept.set(false);
        }
return di;
}// end interrupt
}// end class

And I do this in some other class1

//class1 stuff
JdbcInterceptor.getInstance().skipIntercept();
if(JdbcInterceptor.getInstance().interrupt())
{ // class1 stuff happens
}

Now I do this in class2

//class2 stuff
if(JdbcInterceptor.getInstance().interrupt())
{ // class2 stuff happens
}

Now I am in a bit of confusion, I know that class1 stuff will happen because I set the dontIntercept ThreadLocal. My doubt is whether class2 stuff will happen or not ? My logic is that I have only one instance of JdbcInterceptor so the same state should be available across all calls to interrupt(). But I have been told that ThreadLocals are local for each thread. I see some conflict here. Please help me on this.

+2  A: 

Your question is not very clear.

But I have been told that ThreadLocals are local for each thread. I see some conflict here.

This is correct. There is no conflict. The value object stored with a ThreadLocal is unique to each thread. It is actually stored with the Thread object internally so when a thread terminates all the thread local values also are removed and available for garbage collection unless there are other references to them from other threads.

If both of your classes are executed with the same thread then both will have the same result unless you change the value of the thread local between calls. If a different thread executes class2 then the two would have different values (per your example).

You are perhaps confusing thread execution which occurs in time and classes/methods storage and code. These two are very different. One thread can execute any and all methods or you could have many threads executing the same method in a single class. You cannot "see" threads in your code. Without some other picture you must imagine them - it does take some careful visualization.

Now you can make your code a little clearer by using a ThreadLocal initializer, like this:

private static ThreadLocal<Boolean> dontIntercept = new ThreadLocal<Boolean>() {

    @Override
    protected Boolean initialValue() {
        return Boolean.FALSE;
    }

};

Then when you use the thread local you do not have to check if it is null, like so:

public boolean interrupt() {
    return dontIntercept.get().booleanValue();
}// end interrupt

Here's an attempt to show how this could execute with more two threads:

 Thread1 start---class1(skip=false)-+-skip(true)---+class1(true)--+class2(true)----+-end
                    |               |              |              |                |
                    Thread2 start---+-class1(false)+--------------+class2(false)---+-class1(false)---end

When I show classN(val), the value is what the skip thread local variable is set to at that time.

To more specifically answer your question then in this example: class1 and class2 code will both be skipped when executed by thread1. When executed by thread2 they would not be skipped.

Note that there is another kind of thread local called InheritableThreadLocal. This would behave differently in my example as Thread2 would inhert the value as was in Thread1 at the time that thread started the second thread.

Edit If your code in class1 always sets the skip value to true then the behavior changes a little. If a thread first executes class1 then class2 then skip will be true for both. If a thread first executes class2 and then class1 then skip will be false for the former and true for the later. You do not show that there is a way to turn skip back to false.

Edit Reread your question. If you in fact want the exact same state for all threads then you would not use a ThreadLocal. Just use a regular variable and either mark it as volatile or guard it with synchronization.

Kevin Brock
By conflict I mean the conflict between having only one instance of the class returning different values of a member variable.
Ravi Gupta
Edited code to show how I am setting skip to false.
Ravi Gupta
It's not a conflict if that's what you intend. ThreadLocals are used for that purpose. With the new code the sequence of events is different since executing in class1 the value is always set to `true`, the method skipped, and then reset to `false`. With the new code there is no reason for that - just remove the code in class1 and remove the `if` check in class2.
Kevin Brock