The well acclaimed book JCIP says this about ThreadLocal usage :
It is easy to abuse ThreadLocal by treating its thread confinement property as a license to use global variables or as a means of creating "hidden" method arguments. Thread-local variables can detract from reusability and introduce hidden couplings among classes, and should therefore be used with care.
What does it mean by saying that Thread-local variables can reduce reusability and introduce hidden couplings among classes?
They reduce reusability in much the same way that global variables do: when you method's computations depend on state which is external to the method, but not passed as parameters (i.e. class fields for example), your method is less reusable, because it's tightly coupled to the state of the object/class in which it resides (or worse, on a different class entirely).
Edit: Ok, here's an example to make it more clear. I've used ThreadLocal
just for the sake of the question, but it applies to global variables in general. Assume I want to calculate the sum of the first N integers in parallel on several threads. We know that the best way to do it is to calculate local sums for each thread and them sum them up at the end. For some reason we decide that the call
method of each Task
will use a ThreadLocal sum
variable which is defined in a different class as a global (static) variable:
class Foo {
public static ThreadLocal<Long> localSum = new ThreadLocal<Long>() {
public Long initialValue() {
return new Long(0);
}
};
}
class Task implements Callable<Long> {
private int start = 0;
private int end = 0;
public Task(int start, int end) {
this.start = start;
this.end = end;
}
public Long call() {
for(int i = start; i < end; i++) {
Foo.localSum.set(Foo.localSum.get() + i);
}
return Foo.localSum.get();
}
}
The code works correctly and gives us the expected value of the global sum, but we notice that the class Task
and its call
method are now strictly coupled to the Foo
class. If I want to reuse the Task
class in another project, I must also move the Foo
class otherwise the code will not compile.
Although this is a simple example complicated on purpose, you can see the perils of "hidden" global variables. It also affects readability, since someone else reading the code will have to also search for the class Foo
and see what the definition of Foo.localSum
is. You should keep your classes as self-contained as possible.
A ThreadLocal
is declared per thread - normally a field is declared per object of that class - Starting from this - there can be a whole lot of things that can go wrong if the ThreadLocal
is misused.
If a thread passes through multiple objects , ( either of the single class or multiple classes ) , the ThreadLocal
used by this thread is the same instance across all these instances. This is the coupling BG is talking about. The moment there is a coupling - the reusability becomes difficult and error prone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With