ThreadLocal的原理和使用

引子

前几天有一篇文章分享了SimpleDateFormat类在多线程情况下不安全的问题,文章中也提到了使用ThreadLocal来解决的这种办法,今天就来给大家介绍一下ThreadLocal。

由于SimpleDateFormat类线程不安全,所以我们不能用public static修饰一个SimpleDateFormat变量来共多个线程使用。

既然多个线程不能公用同一个SimpleDateFormat对象,那么每次使用到SimpleDateFormat类的时候new一个新的对象出来就能解决并发问题。

但是SimpleDateFormat类只是在多线程场景下不安全,单线程的使用场景下它还是很优秀的,所以一个线程多次创建SimpleDateFormat对象会显得浪费资源。

既然多线程下不安全,每次需要使用时new新对象又浪费资源,那么有一个新的思路就是在每个线程中都创建一个SimpleDateFormat对象,每次需要使用它的时候从线程中取,这样就很合理的解决了我们的问题了。

作用

ThreadLocal,叫做线程本地变量。ThreadLocal会为变量在每个线程中都创建了一个副本,每个线程可以访问自己内部的副本变量。我们可以把ThreadLocal可以比喻成一个盒子,每个线程有一个自己的盒子存储自己的私有数据

当然了,由于ThreadLocal会占用线程的内存,所以过度的使用ThreadLocak会导致内存资源的浪费。

原理

首先,在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。
- 初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。
- 然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找。
- 没有set之前直接get,返回值null,想要解决这个问题,可以重写initialValue()方法给予默认值。

public class Run {
    public static void main(String[] args) {
        System.out.println(ThreadLocalTest.threadLocal.get());
    }
}

class ThreadLocalTest {
    public static ThreadLocal<String> threadLocal = new ThreadLocal<String>(){
        protected String initialValue() {
            return "Hello World";
        };
    };
}

喜欢这篇文章的朋友,欢迎长按下图关注公众号lebronchen,第一时间收到更新内容。
扫码关注

猜你喜欢

转载自blog.csdn.net/Leon_cx/article/details/81368963