ThreadLocal 源码解析

Posted 你携秋月揽星河丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadLocal 源码解析相关的知识,希望对你有一定的参考价值。

1 简介

ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

2 demo

ThreadLocal 作用: 人手一份。

public class ThreadLocalTest 


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


    private static void setValue(Integer value) 

        threadLocal.set(value);

    

    public static void main(String[] args) throws InterruptedException 


        Thread t1 = new Thread(() -> 
            try 
                setValue(1);
                System.out.println(Thread.currentThread().getName() + " thread local is: " + threadLocal.get());
             finally 
                threadLocal.remove();
            
        , "t1");

        Thread t2 = new Thread(() -> 
            try 
                setValue(2);
                System.out.println(Thread.currentThread().getName() + " thread local is: " + threadLocal.get());
             finally 
                threadLocal.remove();
            
        , "t2");

        Thread t3 = new Thread(() -> 
            try 
                setValue(3);
                System.out.println(Thread.currentThread().getName() + " thread local is: " + threadLocal.get());
             finally 
                threadLocal.remove();
            
        , "t3");


        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();

    


3 ThreadLocal 源码解析

3.1 ThreadLocalMap

(1) ThreadLocalMap
ThreadLocalMap 是ThreadLocal的内部静态类。key是虚引用的ThreadLocal,value是一个Object。

(2) ThreadLocalMap 和 Thread之间的关系

每一个Thread都有一个ThreadLocalMap。

3.2 set

   public void set(T value) 
        //1 获取当前线程
        Thread t = Thread.currentThread();
        //2 获取线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //3 如果map不为空给map设置值,key是当前创建的threadLocal,如果map为空创建map
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    

 void createMap(Thread t, T firstValue) 
 		// ThreadLocal.ThreadLocalMap threadLocals 赋值
 		// 每个线程都有自己的ThreadLocalMap(人手一份)。
        t.threadLocals = new ThreadLocalMap(this, firstValue);
 

3.3 get

public T get() 
		//获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //如果map不为空
        if (map != null) 
             //获取value
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) 
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            
        
        //初始化ThreadLocalMap
        return setInitialValue();
    

3.4 remove

 public void remove() 
 		//获取当前线程的ThreadLocalMap
         ThreadLocalMap m = getMap(Thread.currentThread());
         //如果m!=null  移除
         if (m != null)
             m.remove(this);
     

3.5 ThreadLocalMap 为什么使用弱引用?

防止ThreadLocal对象无法被回收。
每个Thread中都存在一个ThreadLocalMap,并且ThreadLocalMap中的key是以threadlocal实例。每个key都弱引用指向threadlocal。所以当把threadlocal实例置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal就可以顺利被gc回收。
假如每个key都强引用指向threadlocal,那么这个threadlocal就会因为和entry存在强引用无法被回收,造成内存泄漏。除非线程结束,线程被回收了,map也跟着回收。

以上是关于ThreadLocal 源码解析的主要内容,如果未能解决你的问题,请参考以下文章

ThreadLocal源码解析-Java8

ThreadLocal源码解析

JDK1.8中ThreadLocal源码解析

JDK1.8中ThreadLocal源码解析

ThreadLocal源码解析

ThreadLocal源码解析