Using ThreadLocal in Instance Variables

Do Java variables provide ThreadLocallocal stream values ​​if they are used as instance variables (for example, in a method that generates stream-local objects), or should they always be static like that?

As an example, suppose that a typical scenario is when several, expensive for initializing class objects that are not thread safe, need to be created in one static initialization block, stored in static variables of the same class (for example, in a data structure Map), and then used for intensive processing many different threads.

To ensure thread safety, obviously, another copy of each static object must be passed. For example, Java objects DateFormatthat must be safely used for different threads.

In many examples that can be found on the Internet, the approach seems to declare each variable separately ThreadLocal, instantiate a new object in the method initialValue(), and then use the method get()to get the stream-local instance.

This approach is not very effective if you need to create tens or hundreds of such objects, each of which has its own initialization parameters. For example, many objects SimpleDateFormatwith a different date pattern each.

If instantiation of objects can be performed in a loop that produces a different value in each iteration, a general method is needed to create local thread instances after each value is created by properly initializing the corresponding object.

Based on the foregoing, the following general static method will not work, because the same link is created every time initialValue () is called:

// 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 is needed to create a new object inside initialValue (). Thus, the only general approach probably uses reflection in a template 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 a type specification in which you can simply use a template ThreadLocalin a loop to declare each variable.

, DateFormat

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);
}

formats , format() parse() DateFormat, .

- ThreadLocal?

+5
2

Java ThreadLocal , .

, . : ThreadLocal , ThreadLocal . .

- ThreadLocal?

.

:

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

, ThreadLocal, get ( ThreadLocal) . , ThreadLocal .

, usecase, - :

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);
        }
    }
}

:

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

  • ThreadLocal
  • DateFormat ( , )
  • DateFormat, .
+7

, ThreadLocal ThreadLocal. , , . ThreadLocal ; , , , ThreadLocal JVM.

A.H. , . , , . - :

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();
    }
}

ThreadLocal .

+7