zoukankan      html  css  js  c++  java
  • 并发编程之ThreadLocal线程本地类

    一、ThreadLocal的本质和内部结构

      ThreadLocal从字面上翻译就是“线程本地变量”。也就是说这个变量是属于当前线程的,其他线程无法进行访问。

      其实本质上ThreadLocal是管理本地线程变量副本这样的一个工具类。用它来维护线程Thread内部的ThreadLocalMap,

      通过ThreadLocal可以存取在map中的值。由于这个Map是在各个线程内部,因此用来保证各个线程之间的变量互不干扰。

      所以总的来说

      ThreadLocal不是用来解决多线程下访问共享变量(同一变量)问题的,并发下共享变量的同步问题要靠锁来保证

      ThreadLocal用来保证各个线程下的变量互不影响,因为各个变量是保存在Thread内部的Map

      下面展示ThreadLocal的内部结构图

     从上面的结构图可以看出:

    1、每个线程Thread内部都有个Map集合ThreadLocalMap类型

    2、ThreadLocalMap集合内部使用Entry来存储键值对,key为ThreadLocal,value为实际存储的值

    3、通过ThreadLocal可以获取当前线程下的存储的值,从而各个线程互不影响

    二、ThreadLocal类内部代码分析:

     ThreadLocl内部属性与方法如下:

    在其主要用到的方法有:

    get()、set(T)、remove()、initialValue()

    分别是获取当前线程下的变量、设置当前线程下的变量、删除当前线程下的变量、设置初始值

    2.1、get方法

    步骤如下:

    1、获取当前线程变量

    2、根据当前线程,获取其中的ThreadLocalMap对象threadLocals

    3、假如map存在,将threadLocal作为key获得Entry对象

    4、然后判断Entry对象不为空,返回其中的Value

    5、假如map为空或者entry为空则设置初始值然后返回,

       假如不对其中的initialValue进行重写则返回null

    2.2、set方法

     

    步骤如下:

    1、获取当前线程变量

    2、根据当前线程,获取其中的ThreadLocalMap对象threadLocals

    3、假如map不为null,则将threadLocal对象作为key来保存值

    4、假如map为null,则创建map然后塞值保存

    2.3、remove方法

    步骤如下:

    1、获取当前线程的ThreadLocalMap属性threadLocals

    2、然后传入ThreadLocal对象作为key进行remove操作

    三、介绍ThreadLocalMap

    总结:

    1、可以看出ThreadLocalMap并没有继承Map,而是自己实现逻辑

    2、使用内部类Entry来保存值,而Entry是继承弱引用WeakReference,

    3、而且可以看出只有Key是弱引用,并且限定key只能为ThreadLocal类

    3.1、内存溢出问题

    但是由于key是弱引用,可能会出现当ThreadLocal对象没有给强引用时候,

    然后在垃圾回收器进行gc时,发现只有弱引用就会进行回收,

    这样key只会为null,value的值没办法获取造成内存溢出。

    结构图如下:

    可以看出,假如ThreadLocal引用变量并没有强引用ThreadLocal对象的时候,当垃圾回收线程检测到的时候就会回收

    ThreadLocal对象,这样对应的Entry的key为null。

    因此从Thread对象到Object对象这一整引用链中由于key为null,所以没办法获取value。

    并且之间存在强引用也没办法进行回收,这样假如线程周期比较长,会形成内存泄露

    相应的开发团队也考虑到这样的问题,在调用get、set、remove方法的时候内部都会调用

    当key为null的时候设置value为null,并且设置对应的Entry也为null

    且进行遍历所有的key进行上面的清除操作,便于GC进行回收

    但无论如何都好,为了防止内存泄露的问题,但使用完ThreadLocal对象后都要调用remove方法

    本文作者:hjjay
    原文出处:https://www.cnblogs.com/jayhou/p/9811445.html
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

  • 相关阅读:
    WCF在tcp通道下启用httpget
    mounted里面this.$refs.xxx的内容是undefined
    小程序和vue的区别
    多维数组扁平化处理
    浏览器事件循环机制(event loop)
    前端优化总结
    vue子组件通知父组件使用方法
    axios拦截器使用方法
    vue-router配置
    斐波那契数列及青蛙跳台阶问题
  • 原文地址:https://www.cnblogs.com/jayhou/p/9811445.html
Copyright © 2011-2022 走看看