Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does ThreadLocal usage reduce reusability

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?

like image 546
Inquisitive Avatar asked Jul 01 '12 15:07

Inquisitive


2 Answers

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.

like image 128
Tudor Avatar answered Nov 04 '22 07:11

Tudor


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.

like image 38
Bhaskar Avatar answered Nov 04 '22 06:11

Bhaskar