【Java笔记】ThreadLocal入门

第一次见到这个东西,还是写项目中遇见的,了解一下。

在Java多线程模块中,ThreadLocal是经常被提问到的一个只是点,因此只有理解透彻了,不管怎么问,都能游刃有余。

1. ThreadLocal是什么

从名字上我们就可以看出叫做本地线程变量,意思是说,ThreadLocal中填充地是当前线程的变量,该变量对其他线程而言是封闭且隔离地,ThreadLocal为变量在每个线程中创建了一个副本,这样每个线程都可以访问自己内部地副本变量。

从字面意思很容易理解,但是实际角度就没那么容易了,作为一个面试常问的点,使用场景也是很丰富。

  • 在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层级间的约束。
  • 线程间数据隔离
  • 进行事务操作,用于存储线程事务信息。
  • 数据库连接,Session会话管理

2.ThreadLocal怎么用

我们下来看一个例子:

public class demo01 {
    public static void main(String[] args) {
        ThreadLocal<String> local = new ThreadLocal<>();
        IntStream.range(0, 10).forEach(i -> new Thread(() -> {
            local.set(Thread.currentThread().getName() + ":==>" + i);
            System.out.println("线程: " + Thread.currentThread().getName() + ",local: " + local.get());
        }).start());
    }
}

结果

线程: Thread-0,local: Thread-0:==>0
线程: Thread-3,local: Thread-3:==>3
线程: Thread-4,local: Thread-4:==>4
线程: Thread-2,local: Thread-2:==>2
线程: Thread-1,local: Thread-1:==>1
线程: Thread-8,local: Thread-8:==>8
线程: Thread-9,local: Thread-9:==>9
线程: Thread-5,local: Thread-5:==>5
线程: Thread-7,local: Thread-7:==>7
线程: Thread-6,local: Thread-6:==>6

进程已结束,退出代码为 0

从结果可以看出,每一个线程都有自己的local值,这就是ThreadLocal的基本使用。

3.ThreadLocal源码分析

3.1 set方法

下面我们看下源码,了解其工作原理。

public void set(T value) {
    // 首先获取当前线程对象
    Thread t = Thread.currentThread();
    // 获取线程中变量 ThreadLocal.ThreadLocalMap 
    ThreadLocalMap map = getMap(t);
    // 如果不为空,表示当前线程之前已经创建过了,现在重新赋值
    if (map != null) {
        map.set(this, value);
    } else {
        // 如果为空,初始化该线程对象的map变量,其中key为当前的threadlocal变量
        createMap(t, value);
    }
}
// 获取当先线程的ThreadLocalMap对象
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
// ThreadLocal.ThreadLocalMap threadLocals = null;
// threadLocals就是ThreadLocalMap
void createMap(Thread t, T firstValue) {
    // 初始化线程内部变量threadlocals,
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    table = new Entry[INITIAL_CAPACITY];
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    setThreshold(INITIAL_CAPACITY);
}

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

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

汇总下,ThreadLocalMapThreadLocal 的一个静态内部类,里面定义了Entry 来保存数据。而且是继承的弱引用。在Entry内部使用ThreadLocal作为key,使用我们设置的value作为value

对于每个线程内部有个ThreadLocal.ThreadLocalMap 变量,存取值的时候,也是从这个容器中来获取。

3.1 get方法

public T get() {
    // 获取当前线程对象
    Thread t = Thread.currentThread();
    // 获取当前线程的ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

通过上面的分析,相信你对该方法已经有所理解了,首先获取当前线程,然后通过key threadlocal 获取 设置的value

3.3 remove方法

public void remove() {
    //获取当前线程绑定的threadLocals
    ThreadLocalMap m = getMap(Thread.currentThread());
    //如果map不为null,就移除当前线程中指定ThreadLocal实例的本地变量
    if (m != null) {
        m.remove(this);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocalJava中的一个类,用于在多线程环境下实现线程本地变量。它提供了一种线程级别的数据隔离机制,使得每个线程都可以拥有自己独立的变量副本,互不干扰。每个线程都可以通过ThreadLocal对象来访问自己的变量副本,而不会影响其他线程的副本。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java中的ThreadLocal详解](https://blog.csdn.net/licux/article/details/117292777)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [JavaThreadLocal详解(一篇就够了)](https://blog.csdn.net/qq_38721537/article/details/124565091)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [JavaThreadLocal详解](https://blog.csdn.net/qq_53729147/article/details/127967751)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值