java引用类型_Java引用类型

强软弱虚 四种引用类型

1.Java中默认的就是强引用

public class T {

/**

* java垃圾回收时会调用一次且只调用一次

* @throws Throwable

*/

@Override

protected void finalize() throws Throwable {

super.finalize();

System.out.println("finalize执行....");

}

}

*********************************

public class StrongReferenceTest {

public static void main(String[] args) {

T t = new T();

System.gc();

System.out.println(t);

t= null;

System.gc();

System.out.println(t);

}

}

结果:

com.example.reference.T@30946e09

null

finalize执行....

Process finished with exit code 0

强应用,那么如果对象有指向,垃圾回收器将不会回收它。

手动置t为null的话GC回收就会回收该对象

正常情况下,在方法内部有一个强引用,这个引用保存在栈中,而真正的应用内容T保存在堆中,当方法运行结束,就会退出方法栈,引用的变量t就会为null,这个对象就会被回收

但是当为全局变量时,那就不会被回收了。

例如ArrayList的clear()方法,是将每个elementData[i] == null 而非  elementData 对象置为null

8c9c323c4d4f30f4a9e3108de0f73d28.png

2.软引用(SoftReference)

/**

* -Xmx30M

*/

public class SoftReferenceTest {

public static void main(String[] args) {

ReferenceQueue referenceQueue = new ReferenceQueue<>();

SoftReference softReference = new SoftReference<>(new byte[1024*1024*10],referenceQueue);

System.out.println(softReference.get()+"---"+softReference);

System.gc();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(softReference.get()+"---"+softReference);

byte[] bytes2 = new byte[1024*1024*10];

System.out.println(softReference.get()+"---"+softReference);

Reference extends byte[]> poll = referenceQueue.poll();

System.out.println(poll);

}

}

如果一个对象只具有软引用,则内存空间充足时,垃圾回收器不会回收它;如果内存空间不足了,就会回收这些对象的内存,只要垃圾回收器没有回收它,该对象就可以被程序使用

软引用使用场景,做缓存使用。

软引用可以把一个引用队列(ReferenceQueue)联合使用。如果软引用所引用对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中

引用队列的作用:

垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软引用对象,而且虚拟机会尽可能优先回收长时间闲置不用额软引用对象。

对于哪些刚构建的或刚使用过的“较新”软对象会被虚拟机尽可能保留,所以引入引用队列ReferenceQueue的原因

[B@4459eb14---java.lang.ref.SoftReference@5a2e4553

[B@4459eb14---java.lang.ref.SoftReference@5a2e4553

null---java.lang.ref.SoftReference@5a2e4553

java.lang.ref.SoftReference@5a2e4553

1fc900ef1694da0fd618853c67678c58.png

通过结果我们可以分析出,

本身softReference连接SoftReference是强引用(第三行,softReference对象有值,)

SoftReference连接byte[] 是软引用,内存不够后,gc回收(第三行,softReference.get() 结果为null)

垃圾回收也只清除软引用的连接,清除不了强引用

3.弱引用(WeakReference)

弱引用与软引用的区别在于,只具有软引用的对象拥有更短暂的生命周期。

在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存是否足够,都会回收内存。

public class WeakReferenceTest {

public static void main(String[] args) {

// WeakReference weak = new WeakReference(new T());

WeakReference weak = new WeakReference(new String("abc"));

System.out.println(weak.get() + "---" + weak);

System.gc();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(weak.get() + "---" + weak);

System.out.println("***************************");

System.out.println(weak.get() + "---" + weak);

}

}

abc---java.lang.ref.WeakReference@4459eb14

null---java.lang.ref.WeakReference@4459eb14

***************************

null---java.lang.ref.WeakReference@4459eb14

第一次打印出来,第二次打印之前调用gc,所以会打印null值,

weak指向WeakReference弱引用对象,弱引用对象指向new String()对象,gc会把后者的关系给回收。

实际使用场景ThreadLocal

package com.example.reference;

public class ThreaLocalTest {

private static ThreadLocal threadLocal= new ThreadLocal<>();

public static void main(String[] args) throws Exception {

new Thread(()->{

threadLocal.set(Thread.currentThread().getName()+"-----哈哈");

System.out.println("线程1"+threadLocal.get());

}).start();

new Thread(()->{

System.out.println("线程2"+threadLocal.get());

}).start();

Thread.sleep(500);

System.in.read();

}

}

结果:

线程1Thread-0-----哈哈

线程2null

说明第一个线程的set值干扰不到第二个线程的数据正确性

源码分析:

d4fa11e11f0c390504dcc9665f2a1670.png

set方法第一步获取当前线程,然后拿到ThreadLocalMap对象是一个key-value结构,key为this也就是ThreadLocal对象,所以最为关键的是ThreadLocalMap对象如何获取

1c0f1c9e5912f5c98a5ac4889acb9ea3.png

threadLocalMap对象是Thread类的一个属性,所以说天然不同线程互不干扰

c347ad63b3350ee3f15c36ed0b927371.png

分析createMap发现内部new Entry()对象这个对象继承WeakReference 把key放置其中

c6ae5a6929818fcfa860f55cc3e0af0e.png

ThreadLocal关系图如上:

在线程Thread中 定义一个变量 t1强引用new一个对象ThreadLocal

t1.set()会在Thread内部构建一个ThreadLocalMap对象用于存储信息

存储的信息又是构建成一个Entry对象,而entry对象又是继承弱引用对象

t1通过强引用指向ThreadLocal对象,而Map里面的key又是通过弱引用指向ThreadLocal对象。

如果map里面的引用是强引用,那么就是t1使用结束后,退出栈后但是map里面仍然使用强引用关联导致ThreadLocal这个对象始终无法回收,缓存弱引用的话,只要一gc就回收

假设t1的指向被回收,key指向也被回收,key指向一个null,但是这个map仍然存在,里面的value一直存在,且会一直变大。仍然最后导致内存泄漏。

所以ThreadLocal提供了remove方法在方法使用后进行调用

4.虚引用(PhantomReference)

虚引用顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收

虚引用必须和引用队列联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中

虚引用用来管理对外内存,而我们的gc回收的永远是jvm的内存触发不了堆外内存,如果使用虚引用可以以一种别的方式进行内存回收

public class PhantomReferenceTest {

public static void main(String[] args) {

ReferenceQueue queue = new ReferenceQueue();

PhantomReference reference = new PhantomReference<>(new T(),queue);

System.out.println(reference.get()+"----"+reference);

Reference poll = queue.poll();

System.out.println(poll.get());

}

}

null----java.lang.ref.PhantomReference@4459eb14

Exception in thread "main" java.lang.NullPointerException

at com.example.reference.PhantomReferenceTest.main(PhantomReferenceTest.java:13)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值