Java线程局部变量ThreadLocal

本文详细介绍了ThreadLocal类的基本概念和工作原理,包括如何让每个线程绑定自己的值,并提供了ThreadLocal的具体使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ThreadLocal基础

ThreadLocal类可以让每个线程绑定自己的值,它就像一个全局存放数据的盒子,盒子中可以存放每个线程的私有数据。

ThreadLocal类只有一个无参的构造函数,因此实例化ThreadLocal的方法为: new ThreadLocal<T>();

threadLocal.get()方法,取当前线程存放在ThreadLocal里的数据;

threadLocal.set(T value)方法,设置当前线程在ThreadLocal里的数据;

threadLocal.remove()方法,移除当前线程在ThreadLocal里的数据;

threadLocal.initialValue(),返回当前线程在ThreadLocal里的初始值。

类InheritableThreadLocal可以在子线程中取得父线程继承下来的值:在创建子线程时,子线程会接收所有可继承的线程局部变量的初始值,以获得父线程所具有的值。通常,子线程的值与父线程的值是一致的;但是,通过重写这个类中的 childValue 方法,子线程的值可以作为父线程值的一个任意函数。

ThreadLocal源码分析

首先看ThreadLocal类的set方法:

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

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

可以看到它首先获取当前线程对象,然后获取线程对象的threadLocals属性,如果threadLocals为null,就新建一个ThreadLocalMap对象赋值给它,如果不为null,则直接往其上塞值。由此我们可以看到,ThreadLocal本身并不存储数据,数据存储在Thread对象上面。Thread的threadLocals属性是一个ThreadLocal.ThreadLocalMap类型的非静态属性,ThreadLocalMap的实现如下:

static class ThreadLocalMap {

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

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

可以看到ThreadLocalMap的Entry继承了WeakReference,它使用ThreadLocal对象作为key。

再来看ThreadLocal类的get方法:

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();
    }

同样获取当前线程对象,然后获取这个Thread对象的threadLocals,如果不为空,就根据当前ThreadLocal对象key获取值并返回,如果为空,那就设置并返回初始值。

ThreadLocal使用demo

ThreadLocal可以用来存储线程级上下文,一个demo如下:

import java.util.TimeZone;

public class MyContext {

    private ThreadLocal<String> tenantSpaceId;

    private ThreadLocal<TimeZone> userTimeZone;

    private static MyContext instance = new MyContext();

    private MyContext() {
        tenantSpaceId = new ThreadLocal<>();
        userTimeZone = new ThreadLocal<>();
    }

    public static MyContext getInstance() {
        return instance;
    }

    public void setTenantSpaceId(String tsi) {
        tenantSpaceId.set(tsi);
    }

    public String getTenantSpaceId() {
        return tenantSpaceId.get();
    }

    public void setUserTimeZone(TimeZone tz) {
        userTimeZone.set(tz);
    }

    public TimeZone getUserTimeZone() {
        return userTimeZone.get();
    }

    public void clear() {
        tenantSpaceId.remove();
        userTimeZone.remove();
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值