Using ThreadLocal in instance variables
Asked Answered
F

3

5

Do Java ThreadLocal variables produce thread-local values if they are used as instance variables (e.g., in a method that generates thread-local objects), or must they always be static to do so?

As an example, assume a typical scenario where several, expensive to initialize objects of a class that is not thread-safe, need to be instantiated in a single static initialization block, stored in static variables of a single class (e.g., in a Map data structure) and from then on used for intensive processing by numerous different threads.

To achieve thread safety, obviously a different copy of each static object must be passed. For instance, Java DateFormat objects that need to be safely used across different threads.

In many examples one can find on the web, the approach seems to be declaring separately each ThreadLocal variable, instantiate the new object in the initialValue() method and then use the get() method to retrieve a thread-local instance.

This approach is not very efficient if there are dozens or hundreds of such objects to be created, each with its own initialization parameters. For example, many SimpleDateFormat objects with a different date pattern each.

If the instantiation of the objects could be done in a loop which produces a different value in each iteration, a generic method for producing the thread-local instances would be needed, after each value is created by properly initializing the corresponding object.

Based on the above, the following generic static method would not work, because the same reference is produced on every call to initialValue():

// Each value is an object initialized prior to calling getLocal(...)
public static final <T> T getLocal(final T value)
{
    ThreadLocal<T> local = new ThreadLocal<T>()
    {
        @Override
        protected T initialValue()
        {
            return value;
        }
    };

    return local.get();
}

Instead, a mechanism for creating a new object inside initialValue() is needed. So, the only generic approach is probably using reflection, in a pattern similar to

private static final <T> T getLocal(
        final Constructor<T> constructor, final Object[] initargs)
{
    ThreadLocal<T> local = new ThreadLocal<T>()
    {           
        @Override
        protected T initialValue()
        {
            T value = null;

            try // Null if the value object cannot be created
            {
                value = constructor.newInstance(initargs);
            }
            catch (Exception e)
            {
            }

            return value;
        }
    };

    return local.get();
}

Then, of course, there is the type-specific option, where one could just use the ThreadLocal pattern in the loop for declaring each variable.

For example, in the case of DateFormat, in a single, static initialization block, one could do

private static String[] patterns = ... // Get date patterns
private static DateFormat format;

public static Map<String, DateFormat> formats = new HashMap<String, DateFormat>();

static
{
    for (final String pattern:patterns)
    {
        format = new ThreadLocal<DateFormat>()
        {           
                @Override
            protected DateFormat initialValue()
                {
            return new SimpleDateFormat(pattern);
            }
        }.get();

        formats.put(pattern, format);
}

From then on, the formats map will be read by different classes, across different threads, each time in order to invoke the format() or parse() method of one or more DateFormat objects stored in the map.

Does any of the above approaches make sense for the case described, or should the ThreadLocal declarations be static?

Faliscan answered 11/3, 2012 at 11:16 Comment(0)
B
7

Do Java ThreadLocal variables produce thread-local values if they are used as instance variables.

Yes, they do. Think about it: Not the ThreadLocal is static or non-static, only the reference to the ThreadLocal is static or not. The object itself looks always the same.

Does any of the above approaches make sense for the case described, or should the ThreadLocal declarations be static?

Not really.

Example:

[DateFormat] format = new ThreadLocal<DateFormat>()
    {...}.get();
formats.put(pattern, format);

means, that you always create a new ThreadLocal, call get immediately and put the result (not the ThreadLocal) into a map. This means you neither reuse the ThreadLocal nor the format itself.

so, as far as I understand your usecase you might want something like this:

public class XXX {
    private final static Map<String, SimpleDateFormatThreadLocal> formatMap = 
        new HashMap<String, SimpleDateFormatThreadLocal>();

    static {
        String[] patterns = {"a", "b", "c"};
        for(String pattern: patterns){
            formatMap.put(pattern, new SimpleDateFormatThreadLocal(pattern));
        }
    }

    private static class SimpleDateFormatThreadLocal extends ThreadLocal<SimpleDateFormat> {
        private final String pattern;

        public SimpleDateFormatThreadLocal(String pattern) {
            this.pattern = pattern;
        }
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(pattern);
        }
    }
}

Example usage would be like this:

public void run(){
    String s = formatMap.get("a").get().format(new Date());
    System.out.println(s);
}

Here you

  • reuse the ThreadLocal objects
  • reuse the DateFormat objects (per thread of course)
  • avoid creating DateFormats which are not used in some threads.
Baring answered 11/3, 2012 at 12:48 Comment(13)
+1 for a custom subclass of ThreadLocal. I was going to suggest that myself, but you're much faster than i am!Inelegance
@TomAnderson: Interesting... I was about to edit my answer and to remove that subclass for the sake of brevity... But now I'll keep it :-)Baring
I was actually thinking of setting up the instances statically, with a separate variable for each one, in which case having that subclass would save a lot of code (it turns each declaration into a one-liner, rather than a couple of nested blocks). But even using a map, i think it's a decent idea. Although i now notice that i didn't use it in my answer. I'm lazy.Inelegance
@Baring Thanks for the answer. I have updated the example code at the end of my question, to reflect exactly the use case scenario. Is there any way of achieving the same result, without wrapping SimpleDateFormat in another class and without synchronization (used in Tom's answer)?Faliscan
@PNS: Your last edit makes things worse, because you mix up the DateFormat and the ThreadLocal. Also: ThreadLocal is THE dispatcher between ad for different threads. Each thread must go to this dispatcher in order to get a new or recycled DateFormat. There is no way to avoid that overhead, but of course it is good practice to wrap this stuff into a nice class like DateFormatFactory.Baring
I just added "static" to the variable names and some more text describing my use case, nothing else. :-)Faliscan
@PNS: Regarding synchronization: Tom's answer requries synchronization because he assumes, that the patterns are not known upfront. If they are known upfront, you can use the idea of my answer which doesn't require synchronization. But a ThreadLocal wrapper/indirection between the map and the DateFormat is always required.Baring
I don't want to reuse the ThreadLocal objects (if it can be avoided). I just want to initialize several different DateFormat objects and store them in a static variable (DateFormat Map or array). The initialization and storing will happen only once in a single class and, from then on, multiple threads will be using these static DateFormat objects to format() or parse() several strings.Faliscan
@PNS: If you don't want to reuse the TLs, then just remove them completely, as they are useless then (i.e. short-ciruited). And you have to life with multiple threads working on the same DateFormat instance even if you leave the TLs in like in your code. Have fun with that.Baring
This is not fun, which is why I have asked for more expert opinions. I am just (still) trying to find the simplest way of doing this properly. Thanks!Faliscan
@PNS, what do you mean by "I don't want to reuse the ThreadLocal objects"?Inelegance
My usage scenario is very specific (as per the end of my question above) and there is no run() method in my code, as it is called by otherwise instantiated threads. Each of these threads processes several date strings using DateFormat. All I want to do is instantiate a single DateFormat object for every pattern supported and use each such object all the time.Faliscan
A thread-local copy seems to be the solution to avoid synchronization. At the end of the question above I suggest exactly how the DateFormat is to be initialized. What is the simplest way of doing that? If, for every variable threadLocal that wraps a DateFormat object, a threadLocal.get() call is needed, won't it create a new DateFormat object? Or will it just cache the object returned by initialValue()?Faliscan
I
8

To answer your headline question, ThreadLocal provides each thread with a separate value of that ThreadLocal instance. So if you have two instances in different places, each thread will have separate values in each. This is why ThreadLocals are so often static; if all you want is a separate value for a variable per thread, then you only need one ThreadLocal for that variable in the JVM.

A.H.'s answer is very good, and i will suggest a further variation on it. It looks like you might want to put the control over the date formats in the calling code, not in the definition of the map. You could do that with code something like:

public class DateFormatSupplier {
    private static final Map<String, ThreadLocal<DateFormat>> localFormatsByPattern = new HashMap<String, ThreadLocal<DateFormat>>();

    public static DateFormat getFormat(final String pattern) {
        ThreadLocal<DateFormat> localFormat;
        synchronized (localFormatsByPattern) {
            localFormat = localFormatsByPattern.get(pattern);
            if (localFormat == null) {
                localFormat = new ThreadLocal<DateFormat>() {
                    @Override
                    protected DateFormat initialValue() {
                        return new SimpleDateFormat(pattern);
                    }
                };
                localFormatsByPattern.put(pattern, localFormat);
            }
        }
        return localFormat.get();
    }
}

Where you create the ThreadLocals lazily.

Inelegance answered 11/3, 2012 at 12:49 Comment(2)
Thanks! Indeed, I would rather not have a separate class, wrapped around SimpleDateFormat. As I asked A.H. above, is there any way of achieving the same result without synchronization?Faliscan
Yes. You could use a ConcurrentHashMap instead of a plain HashMap, remove the synchronized block, and use putIfAbsent to put new ThreadLocals into the map.Inelegance
B
7

Do Java ThreadLocal variables produce thread-local values if they are used as instance variables.

Yes, they do. Think about it: Not the ThreadLocal is static or non-static, only the reference to the ThreadLocal is static or not. The object itself looks always the same.

Does any of the above approaches make sense for the case described, or should the ThreadLocal declarations be static?

Not really.

Example:

[DateFormat] format = new ThreadLocal<DateFormat>()
    {...}.get();
formats.put(pattern, format);

means, that you always create a new ThreadLocal, call get immediately and put the result (not the ThreadLocal) into a map. This means you neither reuse the ThreadLocal nor the format itself.

so, as far as I understand your usecase you might want something like this:

public class XXX {
    private final static Map<String, SimpleDateFormatThreadLocal> formatMap = 
        new HashMap<String, SimpleDateFormatThreadLocal>();

    static {
        String[] patterns = {"a", "b", "c"};
        for(String pattern: patterns){
            formatMap.put(pattern, new SimpleDateFormatThreadLocal(pattern));
        }
    }

    private static class SimpleDateFormatThreadLocal extends ThreadLocal<SimpleDateFormat> {
        private final String pattern;

        public SimpleDateFormatThreadLocal(String pattern) {
            this.pattern = pattern;
        }
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat(pattern);
        }
    }
}

Example usage would be like this:

public void run(){
    String s = formatMap.get("a").get().format(new Date());
    System.out.println(s);
}

Here you

  • reuse the ThreadLocal objects
  • reuse the DateFormat objects (per thread of course)
  • avoid creating DateFormats which are not used in some threads.
Baring answered 11/3, 2012 at 12:48 Comment(13)
+1 for a custom subclass of ThreadLocal. I was going to suggest that myself, but you're much faster than i am!Inelegance
@TomAnderson: Interesting... I was about to edit my answer and to remove that subclass for the sake of brevity... But now I'll keep it :-)Baring
I was actually thinking of setting up the instances statically, with a separate variable for each one, in which case having that subclass would save a lot of code (it turns each declaration into a one-liner, rather than a couple of nested blocks). But even using a map, i think it's a decent idea. Although i now notice that i didn't use it in my answer. I'm lazy.Inelegance
@Baring Thanks for the answer. I have updated the example code at the end of my question, to reflect exactly the use case scenario. Is there any way of achieving the same result, without wrapping SimpleDateFormat in another class and without synchronization (used in Tom's answer)?Faliscan
@PNS: Your last edit makes things worse, because you mix up the DateFormat and the ThreadLocal. Also: ThreadLocal is THE dispatcher between ad for different threads. Each thread must go to this dispatcher in order to get a new or recycled DateFormat. There is no way to avoid that overhead, but of course it is good practice to wrap this stuff into a nice class like DateFormatFactory.Baring
I just added "static" to the variable names and some more text describing my use case, nothing else. :-)Faliscan
@PNS: Regarding synchronization: Tom's answer requries synchronization because he assumes, that the patterns are not known upfront. If they are known upfront, you can use the idea of my answer which doesn't require synchronization. But a ThreadLocal wrapper/indirection between the map and the DateFormat is always required.Baring
I don't want to reuse the ThreadLocal objects (if it can be avoided). I just want to initialize several different DateFormat objects and store them in a static variable (DateFormat Map or array). The initialization and storing will happen only once in a single class and, from then on, multiple threads will be using these static DateFormat objects to format() or parse() several strings.Faliscan
@PNS: If you don't want to reuse the TLs, then just remove them completely, as they are useless then (i.e. short-ciruited). And you have to life with multiple threads working on the same DateFormat instance even if you leave the TLs in like in your code. Have fun with that.Baring
This is not fun, which is why I have asked for more expert opinions. I am just (still) trying to find the simplest way of doing this properly. Thanks!Faliscan
@PNS, what do you mean by "I don't want to reuse the ThreadLocal objects"?Inelegance
My usage scenario is very specific (as per the end of my question above) and there is no run() method in my code, as it is called by otherwise instantiated threads. Each of these threads processes several date strings using DateFormat. All I want to do is instantiate a single DateFormat object for every pattern supported and use each such object all the time.Faliscan
A thread-local copy seems to be the solution to avoid synchronization. At the end of the question above I suggest exactly how the DateFormat is to be initialized. What is the simplest way of doing that? If, for every variable threadLocal that wraps a DateFormat object, a threadLocal.get() call is needed, won't it create a new DateFormat object? Or will it just cache the object returned by initialValue()?Faliscan
G
1

Caching patterns in a ThreadLocal could be more efficient by using a static ThreadLocal<Map<String, DateFormat>>. Instead of the other way around that you described.

Though if you really need to use ThreadLocals as instance variables (there are cases), consider the following:

One problem with ThreadLocal memory leaks occurs when you initialize instances of ThreadLocals as non static variables. When the object holding that variable is garbage collected, the reference of the ThreadLocal stays in the thread. If you then instantiate and use many ThreadLocals in some kind of loop, you get a memory leak.

I had this problem with FastThreadLocal from netty (and I guess java ThreadLocal should have the same problem). My solution is to use weak referenced map values inside a ThreadLocal to work around this issue. This allows to use ThreadLocal variables as instance variables that can be garbage collected when the holding object is freed.

Here the code (can be used in place of ThreadLocals): https://github.com/invesdwin/invesdwin-util/blob/master/invesdwin-util-parent/invesdwin-util/src/main/java/de/invesdwin/util/concurrent/reference/WeakThreadLocalReference.java

Gleich answered 2/4, 2021 at 21:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.