Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Java's Threadlocal be applied to a non-static field, if yes, how?

ThreadLocal ensures a field is global and local to a thread. (Global because it is available to all methods in the thread and local because it is confined to that thread's stack alone.)

This made little sense to me as each thread's stack is confined to that thread alone. So it is already 'threadlocal', right ?

Why then do we need ThreadLocal ? - On further reading, I confirmed my assumption from various sites (a majority of which fail to provide these facts or contradict each other) that this is indeed applicable for static fields. Which does make sense.

So my question is, is there ever a multi-threading scenario where ThreadLocal can/needs to be applied to non-static fields ? (I came across some sites that say 'ThreadLocal' is "mainly" used for static fields; even https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html uses the word "typically")

like image 303
killjoy Avatar asked May 08 '15 23:05

killjoy


2 Answers

I think that this Question is based on a false premise.

ThreadLocal ensures a field is global and local to a thread. (Global because it is available to all methods in the thread and local because it is confined to that thread's stack alone.)

This is not what "global" really means. Global really means accessible to the entire program without any qualification. And in fact, Java doesn't have true global variables. The closest it has is "public static" fields ... which are accessible with qualification.

But back to the Question ...

A threadlocal variable is available to a method if two conditions are satisfied:

  • The method call must be on the correct thread. (If it is on a different thread, it sees a different variable.)

  • The method must be able to get hold of the ThreadLocal object that effectively "declares" the thread local variable (in any thread).

Does the 2nd condition imply that the "declaration" is global?

IMO, no. For two reasons.

  • Global variables in the conventional sense have only one instance. A thread local has a distinct instance for each thread.

  • The fact that the ThreadLocal is accessible to a specific method does not make it accessible to any method. The normal (and good practice) usage pattern for a ThreadLocal is to hold the object reference in a private static variable. That means that methods in the same class can use the corresponding thread local variable instances ... but methods in other classes can't.

Now it is possible to put the reference to ThreadLocal in a public static variable, but why would you do that? You are explicitly creating a leaky abstraction ... which is liable to cause problems.

And of course, you can do what @Radiodef's answer shows; i.e. create a thread local whose instances are only accessible from methods on a specific instance of a specific class. But it is hard to understand why you would want / need to go to that level of confinement. (And it is liable to lead to storage leaks ...)


Short answer: if you don't want your thread local variables to be accessible, restrict access to the ThreadLocal object.

like image 137
Stephen C Avatar answered Oct 24 '22 09:10

Stephen C


Only local variables are on a thread's stack.* Static variables and instance variables both live on the heap. If we wanted to, we could also just pass a ThreadLocal around by itself without it ever living inside an object or class.

We could view ThreadLocal as a local variable which could be accessible at any point in time.

Normal local variables are destroyed when the scope they are declared in returns, but a ThreadLocal can live anywhere.

So my question is, is there ever a multi-threading scenario where ThreadLocal can/needs to be applied to non-static fields?

We can make one up...

interface Dial {}

class Gadget {
    ThreadLocal<Dial> d = new ThreadLocal<>();
}

class Gizmo implements Runnable {
    Gadget g;
    Gizmo(Gadget g) {
        this.g = g;
    }
    public void run() {}
}

{
    Gadget g = new Gadget();
    new Thread(new Gizmo(g)).start();
    new Thread(new Gizmo(g)).start();
}

Both threads share the same instance of Gadget but has their own local Dial.

Why then do we need ThreadLocal?

The truth is we don't need ThreadLocal very often, if at all.


* Only local variables are on a thread's stack except in the case of a theoretical optimization the JVM is allowed to do where objects can be stack allocated. We would never find out about this if it happened because it would not be allowed to change the behavior of the program. If an object is shared between threads, it's on the heap.

like image 21
Radiodef Avatar answered Oct 24 '22 08:10

Radiodef