前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ThreadLocal源码分析

ThreadLocal源码分析

作者头像
张申傲
发布2020-09-03 11:37:10
2840
发布2020-09-03 11:37:10
举报
文章被收录于专栏:漫漫架构路漫漫架构路

ThreadLocal源码分析

一. 简介

ThreadLocal是JDK提供的一个工具类,其作用是在多线程共享资源的情况下,使每个线程持有一份该资源的副本,每个线程的副本都是独立互不影响的。线程操作各自的副本,这样就避免了资源竞争引发的线程安全问题。

二. 源码分析

ThreadLocal,线程本地变量,该变量为每个线程私有。ThreadLocal类有一个内部类,名为ThreadLocalMap,可以理解为一个简化版的HashMap,它的Key为ThreadLocal实例,Value为ThreadLocal对象所引用的值,源码如下:

代码语言:javascript
复制
static class ThreadLocalMap {
	//该Map的Entry,Key为ThreadLocal实例,Value为ThreadLocal对象所引用的值。
    //这里使用了弱引用,当Entry为null时可以尽快被GC
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

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

    //初始容量16
    private static final int INITIAL_CAPACITY = 16;

    
    private Entry[] table;
}

ThreadLocalMap内部保存了众多的ThreadLocal对象,那么既然说ThreadLocal是线程私有的,那么ThreadLocalMap是存放在哪里呢?

Thread类有一个成员变量——threadLocals,它就是保存了与当前Thread关联的一个ThreadLocalMap,源码如下:

代码语言:javascript
复制
//当前线程内部维护的ThreadLocalMap对象,用于保存所有ThreadLocal实例
ThreadLocal.ThreadLocalMap threadLocals = null;

可以看到,ThreadLocalMap对象保存在了Thread的内部,也即当前线程的私有内存中。

ThreadLocal的主要方法为get()、set()和initialValue()。首先看set():

代码语言:javascript
复制
public void set(T value) {
    //获取当前线程
    Thread t = Thread.currentThread();
    
    //获取当前线程关联的ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    
    //创建一个Entry,以当前ThreadLocal对象为Key,待存储对象为Value,保存在ThreadLocalMap中
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

可以看到,set()的逻辑很简单,从当前线程中获取ThreadLocalMap,然后将该ThreadLocal的值保存在里面。

再看get()方法:

代码语言:javascript
复制
public T get() {
    //获取当前线程对象
    Thread t = Thread.currentThread();
    
    //获取当前线程关联的ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    
    //从ThreadLocalMap获取以ThreadLocal为key的Entry的value
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    
    //如果当前ThreadLocalMap不存在,则调用setInitialValue()方法,获取初始值
    return setInitialValue();
}

ThreadLocal还有一个方法initialValue(),该方法提供给子类覆盖,以在创建ThreadLocal时指定初始值。

四. 应用场景

ThreadLocal最常见的使用场景为管理数据库连接Connection对象等。Spring中使用ThreadLocal来设计TransactionSynchronizationManager类,实现了事务管理与数据访问服务的解耦,同时也保证了多线程环境下connection的线程安全问题。

五. 注意事项

由于ThreadLocal对象会在每个线程中创建一个副本,所以在多线程环境下,如果ThreadLocal所保存的对象过大,可能导致内存的过多占用,需要引起注意。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-11-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ThreadLocal源码分析
    • 一. 简介
      • 二. 源码分析
        • 四. 应用场景
          • 五. 注意事项
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档