How to initialize ThreadLocal objects in Java

24,560

Solution 1

You just override the initialValue() method:

private static ThreadLocal<List<String>> myThreadLocal =
    new ThreadLocal<List<String>>() {
        @Override public List<String> initialValue() {
            return new ArrayList<String>();
        }
    };

Solution 2

The accepted answer is outdated in JDK8. This is the best way since then:

private static final ThreadLocal<List<Foo>> A_LIST = 
    ThreadLocal.withInitial(ArrayList::new);

Solution 3

Your solution is fine. A little simplification:

private static Whatever getMyVariable() 
{
    Whatever w = myThreadLocalVariable.get();
    if(w == null) 
        myThreadLocalVariable.set(w=new Whatever());
    return w; 
} 

In Java 8, we are able to do:

ThreadLocal<ArrayList<Whatever>> myThreadLocal = ThreadLocal.withInitial(ArrayList::new);

which uses the Supplier<T> functional interface.

Share:
24,560
B T
Author by

B T

Updated on June 15, 2020

Comments

  • B T
    B T almost 4 years

    I'm having an issue where I'm creating a ThreadLocal and initializing it with new ThreadLocal . The problem is, I really conceptually just want a persistent list that lasts the life of the thread, but I don't know if there's a way to initialize something per-thread in Java.

    E.g. what I want is something like:

    ThreadLocal static {
      myThreadLocalVariable.set(new ArrayList<Whatever>());
    }
    

    So that it initializes it for every thread. I know I can do this:

    private static Whatever getMyVariable() {
      Whatever w = myThreadLocalVariable.get();
      if(w == null) {
        w = new ArrayList<Whatever>();
        myThreadLocalVariable.set(w);
      }
      return w; 
    }
    

    but I'd really rather not have to do a check on that every time it's used. Is there anything better I can do here?

  • B T
    B T about 11 years
    Interesting comment about Java 8's strange looking ability to initialize less verbosely.
  • ZhongYu
    ZhongYu about 11 years
    Initially it was designed as new ThreadLocal<>( lazyInitializer ). Doug Lea protested that it adds a new field to each ThreadLocal instance. The design was changed to use a factory method, which instantiates a subclass of ThreadLocal. Existing programs that use new ThreadLocal() will still get a good old ThreadLocal instance without any change.
  • kevinarpe
    kevinarpe almost 9 years
    I know this Q&A is a bit old now, but as of writing, the official JDK8 docs have an example in the class description of exactly this -- using initialValue(). Ref: docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html
  • kevinarpe
    kevinarpe almost 9 years
    Also there is now a lambda-friendly static factory method that will help, e.g., ThreadLocal.withInitial(ArrayList::new)
  • user1950349
    user1950349 almost 8 years
    @JonSkeet I am not sure whether I should be using ThreadLocal in one of my SO question here. Wanted to see if you can help out. I haven't got any response yet and I was confuse whether using ThreadLocal is the right option.
  • Michael
    Michael almost 7 years
    Thanks. The field probably shouldn't be capitilised because it's not a constant (the list is mutable). If it were constant, there'd be no need for it to be thread local. You're also using raw types which will introduce a compiler warning. It should be ThreadLocal<List<Foo>>. :)
  • Oliv
    Oliv almost 7 years
    The field is a constant reference, doesn't matter that the referenced object is mutable.
  • Michael
    Michael almost 7 years
    The convention is to capitalise constants, not constant references. See chapter 4 of Effective Java, which is about as authoritative as a Java reference can get: "By convention, such fields have names consisting of capital letters, with words separated by underscores. It is critical that these fields contain either primitive values or references to immutable objects. A final field containing a reference to a mutable object has all the disadvantages of a nonfinal field. While the reference cannot be modified, the referenced object can be modified—with disastrous results."
  • Oliv
    Oliv almost 7 years
    This talks about usage of constants, not the naming style. Whenever a field is static final, it is a constant. Anyway, it's just a convention. I use this one and as far as I remember, most folks do too.
  • Michael
    Michael almost 7 years
    "Whenever a field is static final, it is a constant" hahahaha
  • Oliv
    Oliv over 6 years
    OK, I tried to look up official definition of a constant. Oracle naming conventions don't define it. Checkstyle defines it as "static final field". Google conventions define it as "static final fields whose contents are deeply immutable". So there are contradictions. At least some people (including myself) define it as any "static final" field, so let's put aside this unrelated discussion.
  • Michael
    Michael over 6 years
    Constant: "a situation that does not change". Mutable: "liable to change". If you didn't want to carry on the discussion, you didn't have to reply. It's been months. However, you're wrong and I'm not letting you off the hook that easy ;)
  • Oliv
    Oliv over 6 years
    Is public static final String TABLE_NAME = "myTable" a constant? It's a reference to a DB table, which is mutable. You can dereference it and mutate it. The distinction is set somewhat arbitrarily, that's what I say. Not that you are wrong. But many people define it as I do.
  • Michael
    Michael over 6 years
    Yes, of course that's a constant. It will always represent the string "myTable". The fact that it's used to access some other mutable state is irrelevant. The useful information that's conveyed by the capitalised naming convention is that the object will never change. If it will never change, I know it's inherently thread-safe and can be sure that any interaction will be free from side-effects. I can use it in a pure function. By capitalising mutable static final variables, there is no useful information conveyed about the contents at all and you're undermining the entire point of doing it.
  • Santosh Ravi Teja
    Santosh Ravi Teja about 4 years
    How to specify array list capacity or size like this ArrayList<>(size) ? in this thread local implementaiton ?