TheadLocal源码分析

发布时间 2023-03-22 21:10:57作者: dogtwohaha

TheadLocal源码分析

源码思维导图:https://www.processon.com/view/link/64194d2bc707d756390b0e40

demo案例

@Test
public void testThread() throws InterruptedException {
    HashMap<String, Integer> hashMapA = new HashMap<>();
    HashMap<String, Integer> hashMapB = new HashMap<>();
    HashMap<String, Integer> hashMapC = new HashMap<>();

    Thread threadA = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("A线程开始执行!" + Thread.currentThread().getName());
            hashMapA.put("A线程", 1);
            threadLocal.set(hashMapA);
            Map map = threadLocal.get();
            System.out.println("A线程threadLocal:" + map);
        }
    });
    Thread threadB = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("B线程开始执行!" + Thread.currentThread().getName());
            hashMapB.put("B线程", 1);
            try {
                System.out.println("B线程正在休眠");
                Thread.sleep(300);
                System.out.println("B线程结束休眠");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            threadLocal.set(hashMapB);
            Map map = threadLocal.get();
            System.out.println("B线程threadLocal:" + map);
        }
    });

    hashMapC.put("C线程:", 1);
    threadLocal.set(hashMapC);

    threadA.start();
    threadB.start();
    System.out.println("main线程正在休眠...");
    Thread.sleep(10*60);
    System.out.println("main线程结束休眠...");
    Map map = threadLocal.get();
    System.out.println("main线程开始执行!" + Thread.currentThread().getName());
    System.out.println("main线程threadLocal:" + map);

}

输出

main线程正在休眠...
B线程开始执行!Thread-1
A线程开始执行!Thread-0
B线程正在休眠
A线程threadLocal:{A线程=1}
B线程结束休眠
B线程threadLocal:{B线程=1}
main线程结束休眠...
main线程开始执行!main
main线程threadLocal:{C线程:=1}

table数据

A线程

1679468451957

B线程

1679468502420

main线程

1679468867817

总结: 每个ThreadLocal都会对应一个新的table

1679469405201

看不清楚见思维导图

源码思维导图:https://www.processon.com/view/link/64194d2bc707d756390b0e40

Reference状态

Reference 有五个成员变量:

referent,queue,pending,next,discovered

Reference对象所处状态不同,成员变量的值也会变化。

  • Active: Reference对象新建时处于该状态。

  • Pending: 当Reference包装的referent = null的时候,JVM会把Reference设置成pending状态。如果Reference创建时指定了ReferenceQueue,那么会被ReferenceHandler线程处理进入到ReferenceQueue队列中,如果没有就进入Inactive状态。

  • Enqueue: 进入ReferenceQueue中的对象,等待被回收

  • Inactive: Reference对象从ReferenceQueue取出来并被处理掉。处于Inactive的Reference对象状态不能再改变

    状态的编码由域queue和next共同完成:

    • Active状态
      queue = ReferenceQueue 实例创建时注册;ReferenceQueue.NULL未注册;
      next = null
    • Pengding状态
      queue = ReferenceQueue 实例创建时注册
      next = this
    • Enqueued状态
      queue = ReferenceQueue.ENQUEUEd
      next = queue中下一个实例,若是链表list末尾,则是this
    • Inactive状态
      queue = ReferenceQueue.NULL
      next = this

img

4种引用类型

强,软,弱,虚

1、强引用

例:

Object obj=new Object();
1
强引⽤是使用最普遍的引用。如果⼀个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引⽤的对象来解决内存不足的问题。
1

2、软引用(SoftReference)

例:

Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;
sf.get();//获取对象
1234
如果内存空间不足了,就会回收这些对象的内存。软引用可以和⼀个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加⼊到与之关联的引用队列中。
1

3、弱引用(WeakReference)

例:

Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
wf.get();//获取对象
123
 弱引⽤与软引用的区别在于:只具有弱引用的对象拥有更短暂的⽣命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,⼀旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。弱引⽤可以和⼀个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加⼊到与之关联的引用队列中。
1

4、虚引用(PhantomReference)

例:

Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
12
虚引用在任何时候都可能被垃圾回收器回收,主要用来跟踪对象被垃圾回收器回收的活动,被回收时会收到⼀个系统通知。虚引用与软引用和弱引用的⼀个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收⼀个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加⼊到与之关联的引用队列中。
1

参考:

https://www.jianshu.com/p/802563da6c3a

https://www.jianshu.com/p/d275812816e5

弱引用:https://www.qycn.com/xzx/article/13116.html