ThreadLocal:实现线程间变量隔离

1. ThreadLocal简介

a. ThreadLocal是什么?

ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

b. ThreadLocal的作用

因为每一个Thread内有自己的实例副本,且该副本只能由当前Thread使用。这意味着不存在多线程间共享的问题。通常情况下,ThreadLocal变量会被private static修饰。

c. 为什么要使用ThreadLocal?

总的来说,ThreadLocal适用于每个线程需要自己独立的实例,且该实例需要在多个方法中被使用的情况,也就是变量在线程间隔离而在方法或类间共享的场景。

2. ThreadLocal和Synchronized的区别

a. 相同点

ThreadLocal和Synchronized都用于解决多线程并发访问问题。

b. 不同点

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。Synchronized是利用锁的机制,使变量或代码块在某一时刻只能被一个线程访问。ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,从而隔离了多个线程对数据的共享。而Synchronized正好相反,它用于在多个线程间通信时能够获得数据共享。

c. 简单理解ThreadLocal

一句话理解ThreadLocal:ThreadLocal是作为当前线程中属性ThreadLocalMap集合中的某一个Entry的key值(Entry(ThreadLocal, value))。虽然不同的线程之间ThreadLocal这个key值是一样的,但是不同的线程所拥有的ThreadLocalMap是独一无二的,也就是不同的线程间同一个ThreadLocal(key)对应存储的值(value)不一样,从而达到了线程间变量隔离的目的,但是在同一个线程中这个value变量地址是一样的。

3. ThreadLocal原理

public void set(T value) {
    //1.获取当前线程
    Thread t = Thread.currentThread();
    //2.获取线程中的属性threadLocalMap,如果threadLocalMap不为空,
    //则直接更新要保存的变量值,否则创建threadLocalMap,并赋值
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        // 初始化threadLocalMap 并赋值
        createMap(t, value);
}
 
static class ThreadLocalMap {
 
    /**
     * The entries in this hash map extend WeakReference, using
     * its main ref field as the key (which is always a
     * ThreadLocal object).  Note that null keys (i.e. entry.get()
     * == null) mean that the key is no longer referenced, so the
     * entry can be expunged from table.  Such entries are referred to
     * as "stale entries" in the code that follows.
     */
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;
 
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
}
 
public T get() {
    //1、获取当前线程
    Thread t = Thread.currentThread();
    //2、获取当前线程的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    //3、如果map数据不为空,
    if (map != null) {
        //3.1、获取threadLocalMap中存储的值
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    //如果数据为null,则初始化,
    //初始化的结果,ThreadLocalMap中存放key值为ThreadLocal,值为null
    return setInitialValue();
}
 
private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}
 
public void remove() {
     ThreadLocalMap m = getMap(Thread.currentThread());
     if (m != null)
         m.remove(this);
}


ThreadLocal的实现原理是通过在每个线程中维护一个ThreadLocalMap,其中保存了ThreadLocal作为key和对应的值value。当调用ThreadLocal的set方法时,它会首先获取当前线程,然后从当前线程的ThreadLocalMap中查找是否已经有对应的Entry,如果有,则直接更新值,如果没有,则创建新的Entry并放入ThreadLocalMap中。而调用get方法时,也是首先获取当前线程,然后从ThreadLocalMap中获取对应的值。这种方式保证了每个线程对ThreadLocal的操作都是独立的,不会影响其他线程的值。

4. ThreadLocal与Thread、ThreadLocalMap之间的关系

ThreadLocalMap实际上是Thread线程的一个属性值,而ThreadLocal是维护ThreadLocalMap的工具类。Thread线程可以拥有多个ThreadLocal维护的线程独享的共享变量,每个ThreadLocal对应一个变量。

5. ThreadLocal常见使用场景

a. 每个线程需要有自己单独的实例

b. 实例需要在多个方法中共享,但不希望被多线程共享

ThreadLocal是解决多线程并发访问问题的重要工具之一,特别适用于需要在线程间隔离而在方法或类间共享的场景。通过ThreadLocal,我们可以轻松地实现每个线程拥有自己独立的变量,避免了多线程共享数据的问题,提高了程序的性能和可维护性。希望这篇文章对你理解ThreadLocal有所帮助。

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值