ThreadLocal把变量绑定到线程

本文探讨ThreadLocal的工作原理,解释其如何将变量绑定到线程,确保线程安全而不依赖`synchronized`关键字。ThreadLocal内部维护了每个线程自己的threadLocalMap,通过get和set方法在对应线程的map中存取值,避免锁的开销,提供了一种高效的线程隔离策略。

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

import java.util.Random;

public class ThreadLocalTest {

    static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 123);

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            Random random = new Random();
            while (true) {
                int nextInt = random.nextInt();
                threadLocal.set(nextInt);
                System.out.println("nextInt:" + nextInt + "=" + threadLocal.get());
                try {
                    Thread.currentThread().sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            while (true) {
                Integer integer = threadLocal.get();
                System.out.println("++++++++++++++++++++++++++++++++++++ " + integer);
                threadLocal.set(++integer);
                try {
                    Thread.currentThread().sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread1.start();
        thread2.start();
    }
}

解析:

  • 看到static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 123);是定义了一个静态变量threadLocal
  • thread1不断地通过threadLocal.set(nextInt);设置一个随机整数给静态变量threadLocal
  • thread2Integer integer = threadLocal.get();不断地拿到静态变量threadLocal中的值

结果:

++++++++++++++++++++++++++++++++++++ 123
nextInt:-1877256441=-1877256441
++++++++++++++++++++++++++++++++++++ 124
nextInt:607964023=607964023
++++++++++++++++++++++++++++++++++++ 125
nextInt:1946708981=1946708981
++++++++++++++++++++++++++++++++++++ 126
nextInt:1558534812=1558534812
++++++++++++++++++++++++++++++++++++ 127
nextInt:97463914=97463914

  • 从结果可知,不管线程1如何给同一个静态变量threadLocal赋值,线程2都不会拿到线程1设置的值。
  • 线程2可以拿到自己线程设置的值。

由此可知threadLocal内部的值是绑定到线程的,

对于需要保证线程安全,也就是变量不被其他线程改变,可以使用threadLocal来做同步。

与synchronized不同的是,使用synchronized关键字会导致锁等待造成时间上的开销。
使用ThreadLocal使用的是内存空间的开销。


补充

原理解析:
1、每个存在的线程都维护自己的一个threadLocalMap:

public class Thread {

    Map threadLocalMap = new HashMap();

}

2、哪个线程调用ThreadLocal的get、set方法,就从哪个线程内部的threadLocalMap保存或者获取值:

public class ThreadLocal<T> {

    public void set(T value) {
        Thread currentThread = Thread.getCurrentThread();
        currentThread.threadLocalMap.put(this, value);
    }

    public T get() {
        Thread currentThread = Thread.getCurrentThread();
        return (T) currentThread.threadLocalMap.get(this);
    }
}

测试例子:

public class Test{
    public static void main(String[] args) {
        Thread t1 = null;
        Thread t2 = null;

        ThreadLocal<Integer> threadLocal_1 = new ThreadLocal<Integer>();
        ThreadLocal threadLocal_2 = new ThreadLocal();

        threadLocal_1.set(1);
        threadLocal_2.set(2);

        Integer value_1 = threadLocal_1.get();//1
        Object value_2 = threadLocal_2.get();//2
    }

}

一句话:许多个线程都有自己的map对象,ThreadLocal的set方法实际是调用当前运行线程的map的put方法,以ThreadLocal对象作为key,set的值作为value保存。

因此,一个线程内部的map对象可以保存很多个以ThreadLocal对象作为键的键值对。

因此,一个ThreadLocal对象也可以被很多个线程对象的map作为键值对保存。

因此,ThreadLocal对象的get方法拿到的值,取决于是从哪个线程对象的map中拿。
也就是说,同个ThreadLocal对象,可以在每个线程对象中保存一份值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值