首先再讨论题主的这个观点之前我们要明确一下ThreadLocal的用途是什么?

ThreadLocal并不是用来解决共享对象的多线程访问问题。

看了许多有关ThreadLocal的博客,看完之后会给人一种错觉,ThreadLocal就是用于在多线程情况下防止共享对象的线程安全问题,使用ThreadLocal之后,ThreadLocal的对象就不会有线程安全问题,但是一定是这样么,看如下代码

  1.  
    public class test {
  2.  
    public static void main(String[] args) throws InterruptedException {
  3.  
    new A().start();
  4.  
    new A().start();
  5.  
    new A().start();
  6.  
    new A().start();
  7.  
    }
  8.  
     
  9.  
    static class A extends Thread {
  10.  
    static List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
  11.  
    static ThreadLocal<List<Integer>> threadLocal = new ThreadLocal<List<Integer>>() {
  12.  
    @Override
  13.  
    protected List<Integer> initialValue() {
  14.  
    return list;
  15.  
    }
  16.  
    };
  17.  
     
  18.  
    @Override
  19.  
    public void run() {
  20.  
    List<Integer> threadList = threadLocal.get();
  21.  
    threadList.add(threadList.size());
  22.  
    System.out.println(threadList.toString());
  23.  
    }
  24.  
     
  25.  
    }
  26.  
    }

该代码很简单,就是在多线程的情况下输出ThreadLocal的list集合状态,如果此时线程安全的话,输出的4个语句应该是完全一样的输出结果如下:

[1, 2, 3, 4, 5, 5]
[1, 2, 3, 4, 5, 5, 6]
[1, 2, 3, 4, 5, 5, 6, 7]

[1, 2, 3, 4, 5, 5, 6, 7, 8]

很明显可以看到,线程是不安全的,从结果也能看出来4个线程中ThreadLocal中的List是同一个对象,被四个线程所共享。

接下来我们分析一下原因的发生原因,我们去看ThreadLocal的get()方法

  1.  
    public T get() {
  2.  
    Thread t = Thread.currentThread();
  3.  
    ThreadLocalMap map = getMap(t);
  4.  
    if (map != null) {
  5.  
    ThreadLocalMap.Entry e = map.getEntry(this);
  6.  
    if (e != null) {
  7.  
    @SuppressWarnings("unchecked")
  8.  
    T result = (T)e.value;
  9.  
    return result;
  10.  
    }
  11.  
    }
  12.  
    return setInitialValue();
  13.  
    }

如果一个线程第一次调用threadLocal.get()方法时,我们通过调试可以发现此时拿到的map是null,会调用setInitialValue(),继续看该方法

  1.  
    private T setInitialValue() {
  2.  
    T value = initialValue();
  3.  
    Thread t = Thread.currentThread();
  4.  
    ThreadLocalMap map = getMap(t);
  5.  
    if (map != null)
  6.  
    map.set(this, value);
  7.  
    else
  8.  
    createMap(t, value);
  9.  
    return value;
  10.  
    }

可以看到这个方法里面有一个value,而这个value就是ThreadLocal中即将要保存的只对线程所见的"副本",而这个value使用过initialValue()方法得到的,这个方法如果你没有重写的话默认返回时一个null,而在我们的例子当中他返回的是我们定义的静态变量list,而这个list是一个单例的(只会被类第一次访问时进行初始化),也就是说我们的例子中每个线程的ThreadLocal里面get的都是同一个list,所以就造成了线程安全的问题.

接下来改善一下我们的代码

  1.  
    static class A extends Thread {
  2.  
    static ThreadLocal<List<Integer>> threadLocal = new ThreadLocal<List<Integer>>() {
  3.  
    @Override
  4.  
    protected List<Integer> initialValue() {
  5.  
    return new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
  6.  
    }
  7.  
    };
  8.  
     
  9.  
    @Override
  10.  
    public void run() {
  11.  
    List<Integer> threadList = threadLocal.get();
  12.  
    threadList.add(threadList.size());
  13.  
    System.out.println(threadList.toString());
  14.  
    }
  15.  
     
  16.  
    }

运行结果

[1, 2, 3, 4, 5, 5]
[1, 2, 3, 4, 5, 5]

[1, 2, 3, 4, 5, 5]

[1, 2, 3, 4, 5, 5]

接下来回到主题,ThreadLocal的作用是什么:

ThreadLocal使得各线程能够保持各自独立的一个对象,而实现原理其实是通过,每个线程都会重新创建一个对象,不是什么对象的拷贝或副本,而线程是否安全取决于你如何去创建这个对象。

然后总结一下:

1.ThreadLocal作用不是为了解决共享对象的多线程安全问题,而是为了避免通多参数传递的方式去拿到一个对象,网上有些例子就一开始拿线程安全举例子,然后抛砖引玉出ThreadLocal,会把人带偏。。。博主就是一个。

2.ThreadLocal中保存的不是什么对象的副本,里面没有需要保存的对象做任何复制,拷贝操作,这个对象完全取决于你的iniialtValue方法中如何去创建,所以这里需要考虑使用ThreadLocal的性能问题,是否会大量创建一个对象。

正确理解ThreadLocal:ThreadLocal中的值并不一定是完全隔离的的更多相关文章

  1. 正确理解Spring AOP中的Around advice

    Spring AOP中,有Before advice和After advice,这两个advice从字面上就可以很容易理解,但是Around advice就有点麻烦了. 乍一看好像是Before ad ...

  2. 正确理解web交互中的cookie与session

    cookie存储在客户端的纯文本文件 用户请求服务器脚本 脚本设置cookie内容 并 通过http-response发送cookie内容到客户端并保存在客户端本地 客户端再次发送http请求的时候会 ...

  3. 正确理解ThreadLocal

    想必很多朋友对 ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理 解,然后根据ThreadLocal类的 ...

  4. Java_正确理解ThreadLocal

    首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的.各 ...

  5. java 多线程 :ThreadLocal 共享变量多线程不同值方案;InheritableThreadLocal变量子线程中自定义值,孙线程可继承

      ThreadLocal类的使用 变量值的共享可以使用public static变量的形式,所有的线程都是用同一个public static变量.如果想实现每一个线程都有自己的值.该变量可通过Thr ...

  6. IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

    本文引用了简书作者“骑小猪看流星”技术文章“Cookie.Session.Token那点事儿”的部分内容,感谢原作者. 1.前言 众所周之,IM是个典型的快速数据流交换系统,当今主流IM系统(尤其移动 ...

  7. 正确理解DTO、值对象和POCO

    今天推荐的文章比较技术化也比较简单,但是对于一些初学者而言,可能也是容易搞混的概念:就是如何理解DTO.值对象和POCO之间的区别. 所谓DTO就是数据传输对象(Data Transfer Objec ...

  8. C++ : 从栈和堆来理解C#中的值类型和引用类型

    C++中并没有值类型和引用类型之说,标准变量或者自定义对象的存取默认是没有区别的.但如果深入地来看,就要了解C++中,管理数据的两大内存区域:栈和堆. 栈(stack)是类似于一个先进后出的抽屉.它的 ...

  9. clojure中符号symbols 和变量vars的正确理解

    原地址  http://stackoverflow.com/questions/11662084/why-does-clojure-distinguish-between-symbols-and-va ...

随机推荐

  1. 前端学习笔记2017.6.21-html是个什么东西

    html有两种意思,html语言和html格式 html语言是一种面向人类的计算机语言,这是啥意思?人类用html这种语言描述出一个网页的样子,浏览器解析这个语言并展示出来. html格式是一种文件格 ...

  2. java中的全局变量与静态变量的区别与联系?有时候为什么专门定义静态变量。(标题党~~)

    static代表“每个类一个”而不是“每个对象一个”.即静态变量是类的所有对象共有的. 1 static JFrame f; static MyDrawPanel ml; 整个应用程序如下: 定义在p ...

  3. 1用java实现冒泡排序算法以及解决的几个小问题。

    package huawei.exam; public class BubbleSort { /** * @param args */ public static void main(String[] ...

  4. 一劳永逸搭建android开发环境(android官网reference sample api tutorial全下载)

    [摘要]本文简单介绍了android开发环境的搭建,重点介绍了SDK manager和AVD升级问题:并提供了android reference,sample,api,及docs的下载信息. [1]为 ...

  5. 国外物联网平台(2):微软Azure IoT

    国外物联网平台(2)——微软Azure IoT 马智 平台定位 连接设备.其它 M2M 资产和人员,以便在业务和操作中更好地利用数据. 连接 IoT 设备 将所有设备连接到云,从这些设备接收大规模数据 ...

  6. webapi 返回json

    web api 默认的已 xml 格式返回数据 现在开发一般都是以 json 格式为主 下面配置让 webapi 默认返回 json ,在需要返回 xml 时只需要加一个查询参数 datatype=x ...

  7. cin、cout、cerr、clog------c++ Primer Plus

    cin对象与标准输入流相对应. cout对象与标准输出流相对应. cerr对象与标准错误流相对应,常用于程序错误信息,不缓冲,直接被发送给屏幕. clog对象也对应标准错误流(这点儿和cerr是一样的 ...

  8. python之编辑器pycharm

    在进行python开发的时候,习惯使用pycharm这个编辑器进行开发工作,总结一些常用到的功能点 常用功能: 1. 打开当前文件所在的目录 在文件右击 -> Show in Exploer   ...

  9. ubantu一些资料

    1.在引导页面中选中win10 按E键 进入编辑 在最后一行后面加上一行ntldr /bootmgr 再按F10引导,发现可以进入windows10 2.ubantu安装qq https://lear ...

  10. 第一次接触C++------感触

    2018/09/24 上大学第一次接触C++,感觉还挺有趣的. C语言是计算机的一门语言,顾名思义,语言嘛,有它自己独特的语法. 第一次用C++敲代码,觉得还挺不错的,可以从中找到乐趣.咏梅老师布置的 ...