Using ThreadLocal in instance variables

匆匆过客 提交于 2019-12-03 08:23:23

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.
Tom Anderson

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!