栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

ThreadLocal基本使用与原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ThreadLocal基本使用与原理

ThreadLocal

ThreadLocal可以为不同的线程提供不同变量副本,线程访问threadlocal变量实际上是访问的线程本地的内存中数据副本,线程之间的treadlocal变量互不影响。

基本使用

Example

public class ThreadLocalDemo {

    private static ThreadLocal local = new ThreadLocal<>();

    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println("设置线程1的ThreadLocal变量值");
            local.set("线程1-value");
            String thread2LocalVal = local.get();
            System.out.println("[Thread1]:" + thread2LocalVal);
            local.remove();
            System.out.println("移除线程1的ThreadLocal变量值");
        }).start();

        new Thread(() -> {
            System.out.println("设置线程2的ThreadLocal变量值");
            local.set("线程2-value");
            String thread2LocalVal = local.get();
            System.out.println("[Thread2]:" + thread2LocalVal);
            local.remove();
            System.out.println("移除线程2的ThreadLocal变量值");
        }).start();

    }
}

===========output=============
设置线程1的ThreadLocal变量值
设置线程2的ThreadLocal变量值
[Thread2]:线程2-value
[Thread1]:线程1-value
移除线程2的ThreadLocal变量值
移除线程1的ThreadLocal变量值
ThreadLocal的实现原理

首先我们进入到Thread的源码中看看实现逻辑,在Thread中,存在着名为thredLocals和inheritableThreadLocals的属性:

这两个属性都是 ThreadLocal.ThreadLocalMap类型的,具体由ThreadLocal来负责管理和实现。这个map其实ThreadLocal的定制的HashMap。

从源码中可以看出,每个线程这两个变量的默认值为null,那么他们是何时才初始化赋值的呢?不着急,我们通过基本使用的实例代码打断点,进入ThreadLocal的set方法中,一切都会浮出水面。

set()
    
    public void set(T value) {
        // 获取当前调用该方法的线程
        Thread t = Thread.currentThread();
        // 获取当前线程的threadLocals变量值
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }

源码面前,了无秘密。set方法显而易见,每个线程的threadLocals变量是在线程第一次调用ThreadLocal变量的set方法的时候才进行初始化,并为之赋值的。

inheritableThreadLocals是使得子线程可以从父线程中得到值的设计的。

每张map中维护着当前线程所关联的多个ThreadLocal变量。

get()

get()方法是从线程的ThreadLocal的map中得到对应的值

    public T get() {
        Thread t = Thread.currentThread();
        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();// 实际上返回的是null,不过会执行类似set的操作,创建map对象
    }

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

从源码中,我们可以看到,get方法首先去获得当前调用该threadlocal.get方法的线程,并从该线程中获取到维护着threadlocal的map对象,如果线程的map对象尚未初始化,就执行初始化的操作。并返回null值。

注意

ThreadLocal变量在线程的生命周期中,一旦初始化,是一直存在的,所以可能会造成内存溢出,因此使用完之后,最好调用ThreadLocal的remove方法清除对应线程中的threadLocals的本地变量。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/632072.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号