ThreadLocal源码详解

1 ThreadLocal是用来做什么的(用来解决什么问题)

ThreadLocal解决了基于类级别的变量定义,每一个线程单独维护自己线程内的变量值;其并不能解决并发问题

2 ThreadLocal的使用及简单实现:

使用:

public class ThreadLocalTest {
 private final static ThreadLocal<String> threadLocal=new ThreadLocal<>();

 private final static Random random=new Random(System.currentTimeMillis());
    public static void main(String[] args)throws Exception {
        Thread t1 = new Thread(() -> {
            threadLocal.set("thread-T1");
            try {
                Thread.sleep(random.nextInt(1000));
                System.out.println(Thread.currentThread().getName() + ":" + threadLocal.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t2 = new Thread(() -> {
            threadLocal.set("thread-T2");
            try {
                Thread.sleep(random.nextInt(1000));
                System.out.println(Thread.currentThread().getName() + ":" + threadLocal.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(Thread.currentThread().getName()+""+threadLocal.get());
    }
}

简单实现:

public class ThreadLocalSimulator<T> {
    private final Map<Thread, T> storge = new HashMap<>();

    public void set(T t) {
        synchronized (this) {
            Thread key = Thread.currentThread();
            storge.put(key, t);
        }
    }

    public T get() {
        synchronized (this) {
            Thread key = Thread.currentThread();
            T value = storge.get(key);
            if (value == null) {
                return null;
            }
            return value;
        }
    }
}

3 ThreadLocal的源码的关键实现:

3.1 ThreadLocal的set方法:

源码

 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

 *1 第一步获取当前线程
 *2 利用当前线程获取线程内部的ThreadLocalMap容器,如果没有则创建 
 *3 将变量副本放进去
注意其中的getmap是利用当前线程获取当前线程内的ThreadLocalMap容器

4.2 ThreadLocal的get方法:

源码

 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();
    }

*1 获取当前线程
        *2 从map中根据this(当前的ThreadLocal对象),获取线程存储的Entry节点
        *3 从entry节点中获取对应的value
        *4 如果为空走初始化方法,返回初始值null

4.3 ThreadLocal的remove方法:

public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

*  1 清除Map中的KV,屏蔽内存泄露

4.4 ThreadLocalMap

ThreadLocalMap是ThreadLoca的静态内部类,其关键实现

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

* ThreadLocalMap是一个定制的哈希映射,仅适用于维护线程本地值。ThreadLocalMap类是包私有的,允许在Thread类中声明字段。为了帮助处理非常大且长时间的使用,哈希表entry使用了对键的弱引用。有助于GC回收(key是使用了弱引用当把threadlocal实例置为null以后没有任何强引用指向threadlocal实例所以threadlocal就可以顺利被gc)。但带来了内存泄露的风险(key被回收了,value还可能在存在)

5 ThreadLocal常见问题:

弱引用的好处?(为何使用弱引用)

* 弱引用会将 key设置为null当使用map的get和set方法时会判断key是否为null如果为null则将value设置为 null。弱引用比强引用在 thread 结束之前多一层屏障。

如何解决弱引用?
       * 使用完后,调用threadLocal的remove方法

ThreadLocalMap和Hashmap的区别?
       *  解决了hash冲突;HashMap使用的拉链法,而ThreadLocalMap使用的线性探测法(当我们通过 int i = key.threadLocalHashCode&(len-1)计算出hash值,
       *  如果出现冲突,顺序查看表中下一单元,直到找出一个空单元或查遍全表)

父子线程共享问题? 待补充

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocal源码Java中一个关键的类,它提供了一种在多线程环境下实现线程本地变量的机制。在JDK 8之前和之后,ThreadLocal的内部结构有所变化。ThreadLocal源码分为两部分:ThreadLocal类和ThreadLocalMap类。 ThreadLocal类是一个泛型类,它包含了两个核心方法:set()和get()。set()方法用于将一个值与当前线程关联起来,get()方法用于获取当前线程关联的值。 ThreadLocalMap类是ThreadLocal的内部类,它用于存储每个线程的本地变量。在JDK 8之前,ThreadLocalMap是通过线性探测法解决哈希冲突的,每个ThreadLocal对象都对应一个Entry对象,Entry对象包含了ThreadLocal对象和与之关联的值[2]。 在JDK 8之后,ThreadLocalMap的实现方式发生了改变。使用了类似于HashMap的方式,采用了分段锁的机制来提高并发性能。每个线程维护一个ThreadLocalMap对象,其中的Entry对象也是采用链表的形式来解决哈希冲突。 总结起来,ThreadLocal源码主要由ThreadLocal类和ThreadLocalMap类组成。ThreadLocal类提供了set()和get()方法来管理线程本地变量,而ThreadLocalMap类则负责存储每个线程的本地变量,并解决哈希冲突的问题。 史上最全ThreadLocal 详解 ThreadLocal源码分析_02 内核(ThreadLocalMap) 【JDK源码】线程系列之ThreadLocal 深挖ThreadLocal ThreadLocal原理及内存泄露预防 ThreadLocal原理详解——终于弄明白了ThreadLocal ThreadLocal使用与原理 史上最全ThreadLocal 详解ThreadLocal源码分析,主要有ThreadLocal源码以及ThreadLocal的内部结构在jdk8前后的变化。 使用方式非常简单,核心就两个方法set/get public class TestThreadLocal { private static final ThreadLocal<String> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { try { threadLocal.set("aaa"); Thread.sleep(500); System.out.println("threadA:" threadLocal.get()); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { threadLocal.set("bbb"); System.out.println("threadB:" threadLocal.get()); } }).start(); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值