文档章节

浅谈ThreadLocal

零下三度
 零下三度
发布于 2014/09/10 14:21
字数 1307
阅读 609
收藏 17

      ThreadLocal这个名臣带有一定的迷惑性,千万不要认为ThreadLocal是线程的一种实现,网上很多人认为它应该叫ThreadLocalVariable更贴切,我对此也非常赞同。ThreadLocal存在的意义就是为了解决线程之间数据数据的冲突,ThreadLocal是线程的局部变量,它里面的数据只存活在线程的声明周期之中,而且必须是当前线程才能获取到对应的数据,其他的线程不能获取到当前线程的ThreadLocal中的数据。

       在对ThreadLocal做了一个简单的介绍后,下面开始逐一分析。

1.ThreadLocal是什么?

    ThreadLocal的本质是线程局部变量,可以理解为ThreadLocalVariable,它并非是线程的本地实现,不是一个Thread。

    ThreadLocal的源码中类声明如下:

public class ThreadLocal<T> {...

2.ThreadLocal的作用?

       ThreadLocal存在是为了解决什么问题的呢?在多线程并发的情况下,各个线程的在其上下文环境下保存一些变量副本,

可以独立的改变自己的副本,而不会和其他线程的副本冲突。

       ThreadLocal的数据实际存储在ThreadLocalMap中,并且以当前的ThreadLocal对象作为key,当对ThreadLocal做get和set方法的时候,都是以this为key进行操作的,因此其的ThreadLocal对象获取当前的ThreadLocal对象的值。

    set

 private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

get

  public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }


3.ThreadLocal中的变量存储在何处?

        ThreadLocal中数据式存储在ThreadLocal.ThreadLocalMap中的。这个ThreadLocalMap的对象是被Thread对象的threadLocals的属性引用的。由此可见,ThreadLocal中变量存在Thread对象中,因此在线程的存活期间,如果没有刻意的去删除这些属性,实际上在线程声明周期中均可以对这些变量进行访问和操作。

        ThreadLocalMap是作为Thread类的一个字段。

class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private char	name[];
    private int         priority;
    private Thread	threadQ;
    private long	eetop;

    /* Whether or not to single_step this thread. */
    private boolean	single_step;

    /* Whether or not the thread is a daemon thread. */
    private boolean	daemon = false;

    /* JVM state */
    private boolean	stillborn = false;

    /* What will be run. */
    private Runnable target;

    /* The group of this thread */
    private ThreadGroup	group;

    /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;

    /* The inherited AccessControlContext of this thread */
    private AccessControlContext inheritedAccessControlContext;

    /* For autonumbering anonymous threads. */
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
	return threadInitNumber++;
    }

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
     //请看这里----
    ThreadLocal.ThreadLocalMap threadLocals = null;

         ThreadLocalMap何时创建,并将对象引用和Thread的threadLocals属性关联上呢?在ThreadLocal中有一个createMap的方法,在这个方法里会创建一个ThreadLocalMap。请看下面代码:

void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

         此时还没有回答何时回创建ThreadLocalMap这个问题。实际上在前面的set方法中已经看到调用createMap的方法了,说明在第一设置数据的时候,如果使用当前ThreadLocal对象没有找到ThreadLocalMap对象的时候,那么将会去创建ThreadLocalMap对象,但是起初没有set就开始调用get方法呢?在get方法里面调用一个叫setInitialValue的方法。事实上setInitialValue和set方法非常相似,在setInitialValue中也调用createMap方法。请看下面代码:

 private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

  至此,我可以知道了ThreadLocalMap是存储在Thread对象中,其次TheadLocal会在首次调用get或者set的时候创建ThreadLocalMap对象,并且将这个ThreadLocalMap的对象赋给当前线程的threadlocals属性。

4.ThreadLocal中数据存储详细分析。

    (1)ThreadLocal中数据是存储在ThreadLocalMap的对象中。并且是ThreadLocalMap对象和Thread对象时一对一的关系。

     (2)一个ThreadLocalMap对象对应的ThreadLocal对象是N个。

      (3)ThreadLocalMap的Entry是一个WeakReference<ThreadLocal>子类,ThreadLocalMap中存储的时候是以ThreadLocal的对象作为key,当key释放了引用(key==null),ThreadLocalMap会立刻移除对应Entry。

        我们再次看一下ThreadLocalMap.Entry的声明:

 static class Entry extends WeakReference<ThreadLocal> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal k, Object v) {
                super(k);
                value = v;
            }
        }

5.ThreadLocal回收。参考资料来自ThreadLocal内存泄露

被废弃了的ThreadLocal所绑定对象的引用,会在以下4情况被清理。

如果此时外部没有绑定对象的引用,则该绑定对象就能被回收了:

1 Thread结束时。

2 当Thread的ThreadLocalMap的threshold超过最大值时。

3 向Thread的ThreadLocalMap中存放一个ThreadLocal,hash算法没有命中既有Entry,而需要新建一个Entry时。

4 手工通过ThreadLocal的remove()方法或set(null)。

因此如果我们粗暴的把ThreadLocal设置null,而不调用remove()方法或set(null),那么就可能造成ThreadLocal绑定的对象长期也能被回收,因而产出内存泄露。


© 著作权归作者所有

上一篇: Java中乱码
零下三度
粉丝 8
博文 11
码字总数 13153
作品 0
朝阳
程序员
私信 提问
浅谈Kotlin(一):简介及Android Studio中配置

浅谈Kotlin(一):简介及Android Studio中配置 浅谈Kotlin(二):基本类型、基本语法、代码风格 浅谈Kotlin(三):类 浅谈Kotlin(四):控制流 前言:   今日新闻:谷歌宣布,将Kotli...

听着music睡
2017/05/18
0
0
浅谈java classloader

本文由作者张远道授权网易云社区发布。 类加载器三杰 jvm有三类classloader,分别是bootstrap classloader,extended classloader以及system classloader。 bootstrap classloader是系统在启动...

网易云
2018/12/14
0
0
浅谈Java SE新版本发布线路图

Java SE 9发布于2017年09月22日,也就是从这个版本开始,Java版本遵循半年一个版本的更新速度,Oracle将每三年指定一个版本作为长期支持(LTS)版本。到目前为止,已经发布了Java SE 10和Jav...

韬声依旧在路上
2018/09/30
0
0
浅谈Kotlin(二):基本类型、基本语法、代码风格

浅谈Kotlin(一):简介及Android Studio中配置 浅谈Kotlin(二):基本类型、基本语法、代码风格 浅谈Kotlin(三):类 浅谈Kotlin(四):控制流 通过上面的文章,在Android Studio中我们已...

听着music睡
2017/05/19
0
0
浅谈Scala的特质(trait)

虽然scala的特征相当于Java的接口,但是在使用上,我觉得scala的特征更像抽象类。 比如我们要开发一个2D图形库,必然涉及到矩形对象的定义。 一个矩形可以由对角线上的两个端点唯一确定。矩形...

mj4738
2011/11/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

安得一颗光明心——《王阳明大传》的读后感作文4100字

安得一颗光明心——《王阳明大传》的读后感作文4100字: 偶然听到一个关于王阳明的讲座,简直让我入了迷。多年前接触到阳明,是在思想史中读到的对阳明心学的介绍,晦涩难懂的学术词汇,让我...

原创小博客
8分钟前
0
0
单点登录-基于Redis+MySQL实现单点登录(SSO)

1. 为什么要用单独登录? 主要便于公司内部多系统统一认证授权管理,一次登录可访问多个跨域系统,也同时更加方便统一管理用户登录(员工离职需要拿掉登录权限、统计所有用户对系统的登录请求...

秋日芒草
21分钟前
1
0
827. Making A Large Island

思想: 将所有连通的 1 分成一个组,分配编号,然后使用BFS统计1的个数,得到这个组的面积。 遍历格子里所有为 0 的元素,检查四个方向的1所在的组并加上这个组面积。于是得到当前元素为 0 ...

reter
29分钟前
1
0
亿万pv的混合云规划实施

基础服务: keepalive,lvs,nginx,dns,ntp,redis集群,yum仓库,web资源 网络高可用 防火墙冗余,交换机堆叠 专线互联 物理机虚拟化 VMware vcenter/ Proxmox...

以谁为师
55分钟前
4
0
聊聊dubbo的LRUCache

序 本文主要研究一下dubbo的LRUCache LRUCache dubbo-2.7.2/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java public class LRUCache<K, V> extends LinkedHashMap<......

go4it
57分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部