专栏首页漫漫架构路ThreadLocal源码分析

ThreadLocal源码分析

ThreadLocal源码分析

一. 简介

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

二. 源码分析

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

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,源码如下:

//当前线程内部维护的ThreadLocalMap对象,用于保存所有ThreadLocal实例
ThreadLocal.ThreadLocalMap threadLocals = null;

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

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

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()方法:

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所保存的对象过大,可能导致内存的过多占用,需要引起注意。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 讲透ThreadLocal

    ThreadLocal是JDK提供的一个工具类,其作用是在多线程共享资源的情况下,使每个线程持有一份该资源的副本,每个线程的副本都是独立互不影响的。线程操作各自...

    张申傲
  • MySQL的锁

    数据库锁设计的初衷是处理并发问题。作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则的重要数据结构。根...

    张申傲
  • Redis哨兵机制

    张申傲
  • 深入理解ThreadLocal:拨开迷雾,探究本质

    本文将带领读者深入理解ThreadLocal,为了保证阅读质量,我们可以先一起来简单理解一下什么是ThreadLocal?如果你从字面上来理解,很容易将Thre...

    itlemon
  • 深入理解ThreadLocal:拨开迷雾,探究本质

    本文将带领读者深入理解ThreadLocal,为了保证阅读质量,我们可以先一起来简单理解一下什么是ThreadLocal?如果你从字面上来理解,很容易将Thre...

    itlemon
  • 深入理解ThreadLocal:拨开迷雾,探究本质

    > ThreadLocal是JDK1.2提供的一个工具,它为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,解决共...

    itlemon
  • 抛出这8个问题,检验一下你到底会不会ThreadLocal,来摸个底~

    ThreadLocal类是用来提供线程内部的局部变量。让这些变量在多线程环境下访问(get/set)时能保证各个线程里的变量相对独立于其他线程内的变量。

    Java编程指南
  • ThreadLocal 如此简单

    ThreadLocal提供了线程的局部变量,每个线程都可以通过set()和get()来对这个局部变量进行操作,但不会和其他线程的局部变量进行冲突,实现了线程的数...

    大师兄Eric
  • 聊聊ThreadLocal那些事

    这篇文章聊聊 ThreadLocal,我们经常会在一些开源中间件的源码中见到它的身影,比较常见的用途是保存上下文信息,还有就是保证了线程安全。

    pjmike
  • 手撕面试题ThreadLocal!!!

    讨论ThreadLocal用在什么地方前,我们先明确下,如果仅仅就一个线程,那么都不用谈ThreadLocal的,ThreadLocal是用在多线程的场景的!!...

    纯洁的微笑

扫码关注云+社区

领取腾讯云代金券