ThreadLocal - ThreadlMap与弱引用

2023-11-07

ThreadLocal源码

在看ThreadLocal源码的时候,其中嵌套类ThreadLocalMap中的Entry继承了WeakReferenc

static class ThreadLocalMap {
  static class Entry extends WeakReference<ThreadLocal<?>> {
      /** The value associated with this ThreadLocal. */
      Object value;
      Entry(ThreadLocal<?> k, Object v) {
          super(k);
          value = v;
      }
  }

下面进入正题,WeakReference如字面意思,弱引用, 当一个对象仅仅被weak reference(弱引用)指向, 而没有任何其他strong reference(强引用)指向的时候, 如果这时GC运行, 那么这个对象就会被回收,不论当前的内存空间是否足够,这个对象都会被回收。

从认识WeakReference开始

弱引用对象,它不阻止它们的引用对象被设定为 finalizable, finalized, and reclaimed。弱引用最常用于实现规范化映射。假设垃圾收集器在某个时间点确定一个对象是弱可达的。此时,它将自动清除对该对象的所有弱引用,以及对任何其他弱可达对象的所有弱引用,而该对象可通过强和软引用链访问。同时,它将声明所有以前弱可达的对象为可终结的。在同一时间或稍后的某个时间,它将对那些注册在引用队列中的新清除的弱引用进行排队。

public class WeakReference<T> extends Reference<T> {

    /**
     * Creates a new weak reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new weak reference will refer to
     */
    public WeakReference(T referent) {
        super(referent);
    }

    /**
     * Creates a new weak reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new weak reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required   
     */
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

引用对象的抽象基类。该类定义了所有引用对象的通用操作。因为引用对象是与垃圾收集器密切合作实现的,所以不能直接对该类进行子类化。

public abstract class Reference<T> {
     private T referent;         /* Treated specially by GC */
     //要注册引用的队列,或null如果不需要注册
    volatile ReferenceQueue<? super T> queue;
    
     /* When active:   NULL
     *     pending:   this
     *    Enqueued:   next reference in queue (or this if last)
     *    Inactive:   this
     *  四种状态
     */
    @SuppressWarnings("rawtypes")
    Reference next;


    /* When active:   next element in a discovered reference list maintained by GC (or this if last)
     *   pending:   next element in the pending list (or null if last)
     *   otherwise:   NULL
     */
    transient private Reference<T> discovered;  /* used by VM */
 /**
   * 返回该引用对象的referent。如果该引用对象已经被清除,或者被程序或垃圾收集器清除,然后此方法返null
   */  
 public T get() {
        return this.referent;
    }
}

    /* 
     *   pending:   next element in the pending list (or null if last)
     *   otherwise:   NULL
     * 
     */
  public void clear() {
        this.referent = null;
    }

关于弱引用的测试

通过finalize 自救,再次对finalize对象赋值,来保证此次gc不会回收对象,但是finalize方法只会执行一次

public class TestFinalize {
    private static TestFinalize finalize;

    /**
     * 覆盖finalize,在回收的时候会执行。
     * 只会执行一次
     *
     * @throws Throwable
     */
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("TestFinalize: 执行 finalize 方法");
        finalize=this;
    }



    public static void main(String[] args) throws InterruptedException {
        TestFinalize.finalize = new TestFinalize();
        finalize=null;
        //手动触发一次gc
        System.gc();

        Thread.sleep(3000);

        System.out.println("第一次gc后"+ TestFinalize.finalize);

        finalize=null;
        System.gc();
        Thread.sleep(3000);
        System.out.println("第二次gc后"+ TestFinalize.finalize);
    }
}

entry.get()=null,仅仅回收被弱引用的对象,而不是回收弱引用对象,如下使用弱引用引用对象

public class NullReference {
    private String name;

    public NullReference() {
    }

    public NullReference(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

   @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("TestFinalize: 执行 finalize 方法 name:"+name);
    }
    @Override
    public String toString() {
        return "NullReference{" +
                "name='" + name + '\'' +
                '}' + ", hashCode:" + this.hashCode();
    }

}
/**
 * 这个时候 NullReference 就成为了 被弱引用的对象
 * 在弱引用回收的时候会回收 NullReference 而不是回收WeakReference 的子类TestWeakReference
 */
public class TestWeakReference extends WeakReference<NullReference> {

    public TestWeakReference(NullReference referent) {
        super(referent);
    }


    public static void main(String[] args) {
        TestWeakReference testWeakReference = new TestWeakReference(new NullReference("被弱引用的对象"));
        //通过WeakReference的get()方法获取Apple
        System.out.println("referent:" + testWeakReference.get());
        //被弱引用的对象 GC直接回收,其他强引用也可以访问
        System.gc();
        try {
            //休眠一下,在运行的时候加上虚拟机参数v,输出gc信息,确定gc发生了。
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //如果为空,代表被回收了
        if (testWeakReference.get() == null) {
            System.out.println("clear referent。");
        }

        System.out.println("TestWeakReference:" + testWeakReference);
    }

}

测试输出结果如下:

"C:\Program Files\Java\jdk1.8.0_341\bin\java.exe" -XX:+PrintGCDetails "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.2\lib\idea_rt.jar=64914:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_341\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\rt.jar;C:\project\fairy-letCode\target\classes;C:\Users\EHUALUL\.m2\local_repo\org\projectlombok\lombok\1.18.12\lombok-1.18.12.jar" com.fairy.letCode.threadLocal.TestWeakReference
referent:NullReference{name='被弱引用的对象'}, hashCode:1956725890
[GC (System.gc()) [PSYoungGen: 3932K->496K(76288K)] 3932K->504K(251392K), 0.0010511 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 496K->0K(76288K)] [ParOldGen: 8K->367K(175104K)] 504K->367K(251392K), [Metaspace: 3138K->3138K(1056768K)], 0.0039893 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
TestFinalize: 执行 finalize 方法 name:被弱引用的对象
clear referent。
TestWeakReference:com.fairy.letCode.threadLocal.TestWeakReference@1540e19d
Heap
 PSYoungGen      total 76288K, used 4587K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space 65536K, 7% used [0x000000076ab00000,0x000000076af7afe0,0x000000076eb00000)
  from space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
  to   space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
 ParOldGen       total 175104K, used 367K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c005bca0,0x00000006cab00000)
 Metaspace       used 3236K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 356K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

测试使用ReferenceQueue,会将回收的弱引用对象注册到Queue

public class TestWeakReferntQueue {
    public static void main(String[] args) {
        ReferenceQueue<NullReference> appleReferenceQueue = new ReferenceQueue<>();
        WeakReference<NullReference> appleWeakReference = new WeakReference<>(new NullReference("青苹果"), appleReferenceQueue);
        WeakReference<NullReference> appleWeakReference2 = new WeakReference<>(new NullReference("毒苹果"), appleReferenceQueue);

        System.out.println("=====gc调用前=====");
        Reference<? extends NullReference> reference = null;
        while ((reference = appleReferenceQueue.poll()) != null ) {
            //不会输出,因为没有回收被弱引用的对象,并不会加入队列中
            System.out.println(reference);
        }
        System.out.println(appleWeakReference);
        System.out.println(appleWeakReference2);
        System.out.println(appleWeakReference.get());
        System.out.println(appleWeakReference2.get());

        System.out.println("=====调用gc=====");
        System.gc();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("=====gc调用后=====");

        //下面两个输出为null,表示对象被回收了
        System.out.println(appleWeakReference.get());
        System.out.println(appleWeakReference2.get());

        //输出结果,并且就是上面的appleWeakReference、appleWeakReference2,再次证明对象被回收了
        Reference<? extends NullReference> reference2 = null;
        while ((reference2 = appleReferenceQueue.poll()) != null ) {
            //如果使用继承的方式就可以包含其他信息了
            System.out.println("appleReferenceQueue中:" + reference2);
        }
    }
}

测试输出结果如下:

"C:\Program Files\Java\jdk1.8.0_341\bin\java.exe" -XX:+PrintGCDetails "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.2\lib\idea_rt.jar=64947:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_341\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_341\jre\lib\rt.jar;C:\project\fairy-letCode\target\classes;C:\Users\EHUALUL\.m2\local_repo\org\projectlombok\lombok\1.18.12\lombok-1.18.12.jar" com.fairy.letCode.threadLocal.TestWeakReferntQueue
=====gc调用前=====
java.lang.ref.WeakReference@74a14482
java.lang.ref.WeakReference@1540e19d
NullReference{name='青苹果'}, hashCode:1735600054
NullReference{name='毒苹果'}, hashCode:21685669
=====调用gc=====
[GC (System.gc()) [PSYoungGen: 3932K->464K(76288K)] 3932K->472K(251392K), 0.0010516 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 464K->0K(76288K)] [ParOldGen: 8K->388K(175104K)] 472K->388K(251392K), [Metaspace: 3143K->3143K(1056768K)], 0.0040658 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
TestFinalize: 执行 finalize 方法 name:毒苹果
TestFinalize: 执行 finalize 方法 name:青苹果
=====gc调用后=====
null
null
appleReferenceQueue中:java.lang.ref.WeakReference@74a14482
appleReferenceQueue中:java.lang.ref.WeakReference@1540e19d
Heap
 PSYoungGen      total 76288K, used 4587K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space 65536K, 7% used [0x000000076ab00000,0x000000076af7afd0,0x000000076eb00000)
  from space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
  to   space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
 ParOldGen       total 175104K, used 388K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c0061178,0x00000006cab00000)
 Metaspace       used 3237K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 356K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

从测试结果可以看到Gc后,如果被引用的弱引用对象的entry.get()=null, 会被回收,而这些弱引用对象会注册到queue中

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ThreadLocal - ThreadlMap与弱引用 的相关文章

随机推荐

  • asp.net zero 8.2 学习-11-Metronic替换google字体,加速网页加载速度

    asp net zero 8 2使用的前端模板是Metronic6 0以上版本 官网的Metronic下载下来 打开很慢主要是加载googole字体耗费时间 这是我之前写的如何在Metronic中替换google字体 Metronic是一款
  • 使用STM32F4XX自带数学库“arm_math.h“

    使用STM32F4XX自带数学库 arm math h STM32 F4属于Cortex M4F构架 这与M0 M3的最大不同就是具有FPU 浮点运算单元 支持浮点指令集 因此在处理数学运算时能比M0 M3高出数十倍甚至上百倍的性能 但是要
  • 什么是低信噪比图像及处理方法

    信号处理领域的信噪比即SNR Singal to Noise Ration 又称讯噪比 即放大器的输出信号的电压与同时输出的噪声电压的比 常常用分贝数表示 设备的信噪比越高表明它产生的杂音越少 一般来说 信噪比越大 说明混在信号里的噪声越小
  • python (一维、二维)列表的初始化

    一维列表的初始化 初始一个长度为5的列表 方式1 a 0 5 0 0 0 0 0 方式2 a 0 for in range 5 0 0 0 0 0 二维列表的初始化 初始一个2 5的列表 方式1 b 0 5 for in range 2 0
  • Hibernate环境搭建(小实例)

    Hibernate是一个开源的对象关系映射框架 在学习之前 首先让我们先了解一下Hibernate环境是如何搭建的 废话不多说 直接进入正题 建项目 引Jar包 首先 我们需要创建一个Java项目 创建好项目之后 就需要引入与Hiberna
  • unity的HDR效果

    http blog csdn net wolf96 article details 44057915 文章开始先放两组效果 文章结尾再放两组效果 本文测试场景资源来自浅墨大神 shader效果为本文效果 HDR 人们有限的视觉系统 只支持1
  • 【DS】单链表@线性表 —— 增删查改

    目录 0 引 1 链表的概念和结构 2 链表的分类 3 链表的实现 3 1 打印 申请新节点 销毁 3 1 1 打印 3 1 2 申请新节点 3 1 3 销毁 3 2 尾插 尾删 3 2 1 尾插 3 2 2 尾删 3 3 头插 头删 3
  • 物联网场景中,我们如何选择时序数据库 ?

    如今时序数据的应用场景十分广泛 许多类型的数据都是时间序列数据 金融市场交易 传感器测量 水冷 高温 地震 服务器监控 CPU 内存 磁盘 资源消耗 能源 电力 人体健康 心率 血氧浓度 网络访问 通过保留数据固有的时间序列性质 我们可以记
  • mysql:ER_TRUNCATED_WRONG_VALUE_FOR_FIELD: Incorrect string value:

    发现某个组件的表单输入报错 Error ER TRUNCATED WRONG VALUE FOR FIELD Incorrect string value xE6 x88 x91 xE4 xBB xAC for column content
  • 【算法与数据结构】235、LeetCode二叉搜索树的最近公共祖先

    文章目录 一 题目 二 解法 三 完整代码 所有的LeetCode题解索引 可以看这篇文章 算法和数据结构 LeetCode题解 一 题目 二 解法 思路分析 本题和这道题类似 算法与数据结构 236 LeetCode二叉树的最近公共祖先
  • Linux下Samba的配置

    参考 http www cnblogs com mchina archive 2012 12 18 2816717 html 前言 为了实现windows 和 Linux以及其他操作系统之间的资源共享 软件商推出nfs 和samba两种解决
  • Air101

    目录 1 合宙Air101 固件编译可参考 PinOut V2 1092400 管脚映射表 PinOut V2 1091800 2 Air103 最新固件下载 固件编译可参考 PinOut V3 21112201 管脚映射表 资料链接 Pi
  • Solid JS基础

    Solid js 用于构建用户界面的声明式 高效且灵活的 JavaScript 库 您可以在 官方教程 中尝试下面提到的部分例子 本文引用并简化了官方教程中的部分例子 本文讲述部分 solid 主要内容 更多详细内容 移步 Solid AP
  • 编码器的使用

    首先来看一下增量式编码器的输出信号和它的信号倍频技术 增量式编码器输出的脉冲波形信号形式常见的有两种 一种是占空比50 的方波 通道A和B相位差为90 另一种则是正弦波这类模拟信号 通道A和B相位差同样为90 对于第1种形式的方波信号 如果
  • MATLAB量化浮点数

    在做算法设计和验证时 常在matlab进行浮点验证 然后量化后在用在FPGA上 对于类似与FIR这些滤波器系数 matlab直接可以export出来 但是在验证麦克风或者ADC出来的24bit补码这类时常常需要使用matlab生成定点数进行
  • 有关DHCP、链路聚合、NAT、ACL、Telnet配置小综合实验

    实验需求 1 局域网中存在VLAN10 VLAN20 VLAN30和VLAN40四个部门 IP网段 应192 168 10 0 24 192 168 20 0 24 192 168 30 0 24 192 168 40 0 24 2 业务V
  • Linux虚拟机 Ubuntu16 cheese命令打开摄像头黑屏,以及mjpg-stream框架不显示视频界面。

    在Linux虚拟机 Ubuntu16打开笔记本的摄像头时 用 ubuntu16的cheese命令显示黑屏 如下图 解决方法 1 查看虚拟机是否已经已连接上摄像头 显示断开连接 连接主机 D 则虚拟机已连接上摄像头 2 确认摄像头 笔记本的摄
  • 搭建环境【2】windows主机和ubuntu互传文件的4种方法

    我的ubuntu系统是安装在 VMware 虚拟机中的 两者之间经常要互传文件 下面介绍4种常用的互传文件方法 1 共享文件夹方式互传 在虚拟机中需要开启共享文件夹的功能 首先虚拟机中的ubuntu要求是已经开机了的状态 然后进行设置 虚拟
  • 山东轻工业学院高校俱乐部主席“我和我的CSDN高校俱乐部”

    今天天气不错 上午收到了CSDN邮寄过来的2012年度优秀主席证书以及奖品 心情也不错 感谢CSDN教育事业部全体同事一年来对我们工作的支持与帮助 同时也感谢那些奋战在一线的兄弟姐妹们 你们为轻工学院CSDN高校俱乐部所做的一切 我永远铭记
  • ThreadLocal - ThreadlMap与弱引用

    ThreadLocal源码 在看ThreadLocal源码的时候 其中嵌套类ThreadLocalMap中的Entry继承了WeakReferenc static class ThreadLocalMap static class Entr