从JDK1.2开始,Java中的引用类型分为四种,分别是:

1.强引用(StrongReference)
  这种引用是平时开发中最常用的,例如 String strong = new String("Strong Reference")当一个实例对象具有强引用时,垃圾回收器不会回收该对象,当内存不足时,宁愿抛出OutOfMemeryError异常也不会通过回收强引用的对象,因为JVM认为强引用的对象是用户正在使用的对象,它无法分辨出到底该回收哪个,强行回收有可能导致系统严重错误。

2.软引用(SoftRefernce)

  如果一个对象只有软引用,那么只有当内存不足时,JVM才会去回收该对象,其他情况不会回收。软引用可以结合ReferenceQueue来使用,当由于系统内存不足,导致软引用的对象被回收了,JVM会把这个软引用加入到与之相关联的ReferenceQueue中。
ReferenceQueue referenceQueue = new ReferenceQueue();
SoftReference<Book> softReference = new SoftReference<>(new Book(), referenceQueue);
Book book = softReference.get();
Reference reference = referenceQueue.poll();

当系统内存不足时,触发gc,这个Book就会被回收,reference 将不为null。

3.弱引用(WeakReference)

  只有弱引用的对象,当JVM触发gc时,就会回收该对象。与软引用不同的是,不管是否内存不足,弱引用都会被回收。弱引用可以结合ReferenceQueue来使用,当由于系统触发gc,导致软引用的对象被回收了,JVM会把这个弱引用加入到与之相关联的ReferenceQueue中,不过由于垃圾收集器线程的优先级很低,所以弱引用不一定会被很快回收。下面通过一个主动触发gc的例子来验证此结论。
ReferenceQueue referenceQueue = new ReferenceQueue();
WeakReference<Book> weakReference = new WeakReference(new Book(), referenceQueue);
Book book = softReference.get();
System.gc();
//Runtime.getRuntime().gc();
Reference reference = referenceQueue.poll();

当然这不是每次都能复现,因为我们调用System.gc()只是告诉JVM该回收垃圾了,但是它什么时候做还是不一定的,但就我测试来看,只要多写几次System.gc(),复现的概率还是很高的。

  PS,

  ThreadLocalMap中的静态内部类Entry类就是继承了WeakRefence<ThreadLocal>这个类在构造方法中

static class ThreadLocalMap {

        static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value; Entry(ThreadLocal<?> k, Object v) {
//调用父类WeakReference的构造方法
super(k);
value = v;
}
}

  

public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
//ThreadLocalMap将ThreadLocal作为key,(注意这个Key有点特殊,这个Key被弱引用关联)
map.set(this, value);
else
createMap(t, value);
}
 private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not. Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
//e最终获取的是其实是被弱引用WeakRerference关联的ThreadLocal
ThreadLocal<?> k = e.get(); if (k == key) {
e.value = value;
return;
} if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
} tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
//Reference中的Get方法
public T get() {
return this.referent;
}

注意:

  由于Thread 线程对象都具有成员变量ThreadLocal.ThreadLocalMap,

  而ThreadLocalMap中的key就是当前ThreadLocal对象,而value就是我们想要和线程上下文绑定的数据,

  同时ThreadLocal又被弱引用关联,

  因此在线程生命周期结束时,其成员变量ThreadLocal.ThreadLocalMap,也会为null,此时内部的Entry会做额外的操作将value置为null,

这样就满足了弱引用被回收的条件:当且仅当Entry的key持有弱引用时,该ThreadLocal就会被回收,解决了ThreadLocal对象内存泄漏的问题;

4.虚引用(PhantomReference)

  如果一个对象只有虚引用在引用它,垃圾回收器是可以在任意时候对其进行回收的,虚引用主要用来跟踪对象被垃圾回收器回收的活动,当被回收时,JVM会把这个弱引用加入到与之相关联的ReferenceQueue中。与软引用和弱引用不同的是,虚引用必须有一个与之关联的ReferenceQueue,通过phantomReference.get()得到的值为null,试想一下,如果没有ReferenceQueue与之关联还有什么存在的价值呢?
 
PhantomReference<Book> phantomReference = new PhantomReference<>(new Book(), referenceQueue);
Book book = phantomReference.get(); //此值为null
Reference reference = referenceQueue.poll();

 

【Java】Java中的四种对象引用的更多相关文章

  1. JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)

    1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...

  2. JAVA中的四种引用以及ReferenceQueue和WeakHashMap的使用示例

    简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用) ...

  3. Java中的四种引用

    引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...

  4. JAVA中的四种JSON解析方式详解

    JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...

  5. java 20 -10 字节流四种方式复制mp3文件,测试效率

    电脑太渣,好慢..反正速率是: 高效字节流一次读写一个字节数组 > 基本字节流一次读写一个字节数组 > 高效字节流一次读写一个字节 > 基本字节流一次读写一个字节 前两个远远快过后面 ...

  6. Java通过Executors提供四种线程池

    http://cuisuqiang.iteye.com/blog/2019372 Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果 ...

  7. JAVA解析XML的四种方式

    java解析xml文件四种方式 1.介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这 ...

  8. 【Java】详解Java解析XML的四种方法

    XML现在已经成为一种通用的数据交换格式,平台的无关性使得很多场合都需要用到XML.本文将详细介绍用Java解析XML的四种方法. AD: XML现在已经成为一种通用的数据交换格式,它的平台无关性,语 ...

  9. java环境变量配置四种方法

    原文:java环境变量配置四种方法 Java编程首要工作就是安装JDK(Java Development Kit).一通“NEXT”点完安装后就是最重要的环境变量设置了.也许有人会问为什么要设置环境变 ...

随机推荐

  1. 后端程序员之路 26、CAP理论

    可能是CAP理论的最好解释 - 西代零零发 - 博客频道 - CSDN.NEThttp://blog.csdn.net/dc_726/article/details/42784237 CAP理论 - ...

  2. android上实现0.5px线条

    转: android上实现0.5px线条 由于安卓手机无法识别border: 0.5px,因此我们要用0.5px的话必须要借助css3中的-webkit-transform:scale缩放来实现. 原 ...

  3. [DP浅析]线性DP初步 - 2 - 单调队列优化

    目录 #0.0 前置知识 #1.0 简单介绍 #1.1 本质 & 适用范围 #1.2 适用方程 & 条件 #2.0 例题讲解 #2.1 P3572 [POI2014]PTA-Littl ...

  4. VSCode添加用户代码片段,自定义用户代码片段

    在使用VScode开发中经常会有一些重复使用的代码块,复制粘贴也很麻烦,这时可以在VScode中添加用户代码片段,输入简写即可快捷输入. VScode中添加用户自定义代码片段很简单. 1.在VScod ...

  5. 一文吃透zabbix4.0的编译安装,最全最详细的安装。

    什么是zabbix? zabbix作为一款企业级,开源的,分布式的监控套件,解决了以往监控软件的短板,可以说是现在流行的监控解决方案之一. 监控系统的理想化模样 1.监控数据收集及可视化. 2.数据要 ...

  6. 解决图片把父元素向下撑大大约3px问题

    现象  bug: 图片在div\li\dt 等  图片把父元素向下撑大大约3px  <style>         img {             width: 30%; //这里由于 ...

  7. SHA算法摘要处理

    byte[] input="sha".getBytes();//待做消息摘要算法的原始信息,可以是任意字符串 MessageDigest sha=MessageDigest.get ...

  8. C# 获取Word文本高亮和背景(附vb.net代码)

    Word中的文本高亮和背景是通过不同方法来设置的.文本高亮(Text Highlight Color)是通过[字体]中的快速工具栏设置:文本背景(Text Background/Shading)是通过 ...

  9. Android Studio 如何更新到新版本

    •How 打开 Android Studio 选择任务栏中的 File 点击 Setting: 来到如下界面: 依次点击  Appearance & Behavior -> System ...

  10. 解决send-mail: fatal: parameter inet_interfaces: no local interface found for ::1

    1:检查sendmail服务的状态 service sendmail status 2:开启sendmail服务 service sendmail start3:关闭sendmail服务 servic ...