有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java ThreadLocal相对于新局部变量的真正优势

我意识到ThreadLocal已经被访问过好几次,尤其是SimpleDataFormat示例

但是,即使将SDF设置为“ThreadLocal”,我们仍然会为每个线程创建一个SDF()实例,这相当于调用一个新的SDF()

执行此操作一次,将为每个线程提供一份SDF副本-

ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>();

这也是-

SimpleDateFormat sdf = new SimpleDateFormat();

线程安全只是通过每次复制SDF来创建的。 因此,在这两种情况下,我们有相同数量的SDF实例

那么,在实例数量方面的改进在哪里呢

如果没有-为什么我要使用ThreadLocal,而不是每次都在线程中执行new SDF()?这样,我也不用担心同步问题

如果这个参数是正确的-我认为使用ThreadLocal的一个原因是它的范围。这是可能的。稍后在代码中的其他地方获取(),而不在参数中传递它

我想确定,我正确理解了这一点

多谢各位


共 (1) 个答案

  1. # 1 楼答案

    TraceLoopes有多种用途,但在包装非线程安全对象的上下文中,请考虑下面的示例。br/> 非线程本地方法最有可能崩溃,而线程本地版本则不会

    public static void main(String... args) {
        MyParser parser = new MyParser();
        IntStream.range(0, 100).parallel().forEach(i-> parser.parseTl("20170816"));
        IntStream.range(0, 100).parallel().forEach(i-> parser.parse("20170816"));
    }
    
    static class MyParser {
        private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        private static final ThreadLocal<SimpleDateFormat> sdftl =
                ThreadLocal.withInitial(()-> new SimpleDateFormat("yyyyMMdd"));
    
        public Date parse(String str) {
            try {
                return sdf.parse(str);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
    
        public Date parseTl(String str) {
            try {
                return sdftl.get().parse(str);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
    }
    

    现在,您只需在每次解析日期时构造一个新的格式化程序:

    public Date parse(String str) {
        try {
            return new SimpleDateFormat("yyyyMMdd").parse(str);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
    

    但是这种方法的问题是构造SimpleDateFormat是一个相对缓慢的操作,因此您希望以最少的次数构造它

    当然,在本例中还有其他选项,您可以同步对格式化程序的访问,但这可能比每个线程都有自己的副本慢得多。 或者可以使用线程安全的Java 8java.time格式化程序