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也跟着回收。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>