ThreadLocal分析

本文通过对比的方式介绍了ThreadLocal在并发编程中的应用,展示了如何利用ThreadLocal为每个线程提供独立的变量副本,避免了多线程间的数据冲突问题。

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

ThreadLocal:线程局部变量

在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用

例子比较:


不使用ThreadLocal时

public class ThreadLocalTest {
    static int a =1;

    public static void main(String[] args) {
        new Thread1().start();
        new Thread2().start();
        new Thread3().start();
    }

}
class Thread1 extends Thread{
    @Override
    public void run() {
        for (int i = 30; i < 40; i++) {
            ThreadLocalTest.a =  i;
        }
        System.out.println("最后1====>"+ThreadLocalTest.a);
    }
}
class Thread2 extends Thread{
    @Override
    public void run() {
        for (int i = 60; i < 70; i++) {
            ThreadLocalTest.a = i;
        }
        System.out.println("最后2====>"+ThreadLocalTest.a);
    }
}
class Thread3 extends Thread{
    @Override
    public void run() {
        for (int i = 80; i < 90; i++) {
            ThreadLocalTest.a = i;
        }
        System.out.println("最后3====>"+ThreadLocalTest.a);
    }
}


结果可以看到

当多个线程访问这个成员变量时,它会被其他线程改变
最后2====>69
最后1====>69
最后3====>89


使用ThreadLocal时

public class ThreadLocalTest {
    static int a =1;

    public static void main(String[] args) {
        new Thread1().start();
        new Thread2().start();
        new Thread3().start();
    }

}
class Thread1 extends Thread{
    @Override
    public void run() {
        for (int i = 10; i < 20; i++) {
            ThreadLocalTest.integerThreadLocal.set(i);
            System.out.println("thread1====>"+ThreadLocalTest.integerThreadLocal.get());
        }
    }
}
class Thread2 extends Thread{
    @Override
    public void run() {
        for (int i = 40; i < 50; i++) {
            ThreadLocalTest.integerThreadLocal.set(i);
            System.out.println("thread2====>"+ThreadLocalTest.integerThreadLocal.get());
        }
    }
}
class Thread3 extends Thread{
    @Override
    public void run() {
        for (int i = 80; i < 90; i++) {
            ThreadLocalTest.integerThreadLocal.set(i);
            System.out.println("thread3====>"+ThreadLocalTest.integerThreadLocal.get());
        }
    }
}


结果可以看到,线程只改变自己线程局部变量的值

thread1====>10
thread1====>11
thread1====>12
thread1====>13
thread1====>14
thread1====>15
thread1====>16
thread1====>17
thread1====>18
thread1====>19
thread3====>80
thread3====>81
thread2====>40
thread2====>41
thread2====>42
thread2====>43
thread3====>82
thread2====>44
thread3====>83
thread2====>45
thread2====>46
thread2====>47
thread2====>48
thread2====>49
thread3====>84
thread3====>85
thread3====>86
thread3====>87
thread3====>88
thread3====>89


ThreadLocal实现原理

1.看源码知道,每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

2.当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。

    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    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();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值