Search code examples
javamultithreadingthread-local

ThreadLocal vs local variable in Runnable


Which one among ThreadLocal or a local variable in Runnable will be preferred? For performance reasons. I hope using a local variable will give more chances for cpu caching, etc.


Solution

  • Which one among ThreadLocal or a local variable in Runnable will be preferred.

    If you have a variable that is declared inside the thread's class (or the Runnable) then a local variable will work and you don't need the ThreadLocal.

    new Thread(new Runnable() {
        // no need to make this a thread local because each thread already
        // has their own copy of it
        private SimpleDateFormat format = new SimpleDateFormat(...);
        public void run() {
           ...
           // this is allocated per thread so no thread-local
           format.parse(...);
           ...
        }
    }).start();
    

    On the other hand, ThreadLocals are used to save state on a per thread basis when you are executing common code. For example, the SimpleDateFormat is (unfortunately) not thread-safe so if you want to use it in code executed by multiple threads you would need to store one in a ThreadLocal so that each thread gets it's own version of the format.

    private final ThreadLocal<SimpleDateFormat> localFormat =
        new ThreadLocal<SimpleDateFormat>() {
            @Override
            protected SimpleDateFormat initialValue() {
                return new SimpleDateFormat(...);
            }
         };
    ...
    // if a number of threads run this common code
    SimpleDateFormat format = localFormat.get();
    // now we are using the per-thread format (but we should be using Joda Time :-)
    format.parse(...);
    

    An example of when this is necessary is a web request handler. The threads are allocated up in Jetty land (for example) in some sort of pool that is outside of our control. A web request comes in which matches your path so Jetty calls your handler. You need to have a SimpleDateFormat object but because of its limitations, you have to create one per thread. That's when you need a ThreadLocal. When you are writing reentrant code that may be called by multiple threads and you want to store something per-thread.

    Instead, if you want pass in arguments to your Runnable then you should create your own class and then you can access the constructor and pass in arguments.

    new Thread(new MyRunnable("some important string")).start();
    ...
    private static class MyRunnable implements {
        private final String someImportantString;
        public MyRunnable(String someImportantString) {
            this.someImportantString = someImportantString;
        }
        // run by the thread
        public void run() {
           // use the someImportantString string here
           ...
        }
    }