ThreadLocal到底是什么?是如何实现的?

ThreadLocal是什么?

ThreadLocal可以给每一个线程分配属于自己的本地变量,让每个线程绑定自己的值,线程之间不互相影响。

ThreadLocal的使用:

创建了ThreadLocal变量之后,可以使用get()和set()方法来获取默认值,或者更改当前线程所保存的副本的值。

举例:

public class ThreadLocalDemo {

    static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

    public static void main(String[] args){
        Thread t1 = new Thread(() -> {
            System.out.println(threadLocal.get());
            threadLocal.set(0);
            System.out.println(threadLocal.get());
        });

        Thread t2 = new Thread(() -> {
            try {
                t1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadLocal.get());
            threadLocal.set(1);
            System.out.println(threadLocal.get());
        });

        t1.start();
        t2.start();
    }
}

运行结果:

null
0
null
1

我们创建了两个线程,在t1中第一次调用threadLocal.get()得到默认值null,然后在t1把threadLocal设置为0,再次get,得到我们刚才设置的0。然后在第二个线程t2中,我们先调用t1.join(),保证在t2中get之前,t1中的threadLocal已经set为0。然后我们再调用t2中的threadLocal.get(),发现得到的还是默认值null,这就说明两个线程中threadLocal是相互独立的,t1之中的threadLocal被设置为1了,但是t2之中的threadLocal并没有受到影响。

ThreadLocal的实现原理:

ThreadLocal是不保存任何值的,真正的值都保存在当前线程里,每一个线程里都有一个类型为ThreadLocalMap的变量threadLocals

ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocalMap我们可以理解为一个hashmap,其中的key是ThreadLocal对象,value就是我们自己set的值。我们创建一个ThreadLocal对象,就相当于创建了一个key,然后调用ThreadLocal.get(),就相当于在当前线程维护的hashmap之中,找到这个key对应的值。举个例子:

public class ThreadLocalDemo {
	//创建两个ThreadLocal,也就是两个key
    static ThreadLocal name = new ThreadLocal();
    static ThreadLocal age = new ThreadLocal();

    public static void main(String[] args){
        Thread t1 = new Thread(() -> {
            //t1之中维护了一个map,保存两个key-value对
            name.set("Tom");
            age.set(18);
            System.out.println(name.get() + "的年龄为" + age.get());
        });

        Thread t2 = new Thread(() -> {
            try {
                t1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //t2之中维护了一个map,保存两个key-value对
            name.set("Jerry");
            age.set(20);
            System.out.println(name.get() + "的年龄为" + age.get());
        });

        t1.start();
        t2.start();
    }
}

运行结果:

Tom的年龄为18
Jerry的年龄为20

每一个线程都维护一个map,我们创建了两个ThreadLocal变量,分别为name和age,当我们在线程t1之中调用name.set(“Tom”)的时候,就相当于把(name,Tom)这个键值对保存到了t1的map下。其他的set、get也都是如此。通过这个例子,就可以很好的理解ThreadLocal的实现原理。

ThreadLocal内存泄漏问题:

经过分析,我们可以知道map键值对是保存在线程中的,并且是一个强引用,也就是说这个map键值对的生命周期是与线程一致的。这样就会造成即使我们回收了ThreadLocall对象,但是map中保存的数据也不会被回收。这样就会造成内存泄漏。

解决方法:每次用完ThreadLocal后手动remove(),回收无用对象。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值