Java中有四种引用类型:强引用、软引用、弱引用、虚引用
Java为什么要设计这四种引用
Java的内存分配和内存回收 都不需要程序员负责 都是由伟大的JVM去负责
一个对象是否可以被回收 主要看是否有引用指向此对象 说的专业点 叫可达性分析
Java设计这四种引用的主要目的有两个:
1)可以让程序员通过代码的方式来决定某个对象的生命周期
2)有利用垃圾回收

1 强引用

new出来的对象都是强引用 垃圾回收器绝不会回收它
比如 **Object o = new Object()**;
当内存空间不足 Java虚拟机宁愿抛出OutOfMemoryError错误 使程序异常终止 也不会靠随意回收具有强引用的对象来解决内存不足问题
那么什么时候才可以被回收呢?当强引用和对象之间的关联被中断了 就可以被回收了
我们可以手动把关联给中断了 方法也特别简单:
o = null;
在实际的开发中 看到有一些对象被手动赋值为NULL 很大可能就是为了“特意提醒”JVM这块资源可以进行垃圾回收了

2 软引用(SoftReference)

下面先来看看如何创建一个软引用:
SoftReference soft=new SoftReference(new User());
软引用就是把对象用SoftReference包裹一下 当我们需要从软引用对象获得包裹的对象 只要调用get()方法就可以了
User user = soft.get();
软引用特点:
当内存不足 会触发JVM的GC 如果GC后 内存还是不足 就会把软引用的包裹的对象给干掉 也就是只有在内存不足 JVM才会回收该对象
只要垃圾回收器没有回收它 该对象就可以被程序使用
软引用作用:
比较适合用作缓存 当内存足够 可以正常的拿到缓存 当内存不够 就会先干掉缓存 不至于马上抛出OOM

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

3 弱引用(WeakReference)

弱引用的使用方式和软引用类似
WeakReference weak = new WeakReference(new User());
弱引用与软引用的区别在于:弱引用的对象拥有更短暂的生命周期
弱引用特点:
不管内存是否足够 只要发生GC 都会被回收
不过 由于垃圾回收器是一个优先级很低的线程 因此不一定会很快发现那些只具有弱引用的对象
弱引用的用处
比如ThreadLocal、WeakHashMap
弱引用可以和一个引用队列(ReferenceQueue)联合使用
如果弱引用所引用的对象被垃圾回收 Java虚拟机就会把这个弱引用加入到与之关联的引用队列中

  1. import java.lang.ref.SoftReference;
  2. import java.lang.ref.WeakReference;
  3. import java.util.*;
  4. import java.util.concurrent.ConcurrentHashMap;
  5. public class TestMain{
  6. public static void main(String[] args) {
  7. //强引用
  8. User user = new User();
  9. //软引用
  10. SoftReference soft = new SoftReference(new User());
  11. //弱引用
  12. WeakReference weak = new WeakReference(new User());
  13. System.out.println("new = "+user);
  14. System.out.println("soft = "+soft.get());
  15. System.out.println("weak = "+weak.get());
  16. //垃圾回收
  17. System.gc();
  18. System.out.println("new = "+user);
  19. System.out.println("soft = "+soft.get());
  20. //弱引用的被回收
  21. System.out.println("weak = "+weak.get());
  22. //模拟内存不足
  23. System.out.println("内存不足");
  24. List list = new ArrayList<>();
  25. try {
  26. while (true) {
  27. list.add(new byte[1024*1024*5]);
  28. }
  29. }catch (Throwable throwable){
  30. System.out.println("new = "+user);
  31. System.out.println("soft = "+soft.get());
  32. System.out.println("weak = "+weak.get());
  33. }
  34. }
  35. }

4 虚引用(理解就行)

虚引用又被称为幻影引用 我们来看看它的使用:

  1. ReferenceQueue queue = new ReferenceQueue();
  2. PhantomReference<Uesr> reference = new PhantomReference<Uesr>(new Uesr(), queue);
  3. System.out.println(reference.get());
  4. //得到的结果为null
  5. //看看get方法的源码
  6. public T get() {
  7.   return null;
  8. }


1)即无法通过虚引用来获取对一个对象的真实引用
2)虚引用必须与ReferenceQueue一起使用
当GC准备回收一个对象 如果发现它还有虚引用 就会在回收之前 把这个虚引用加入到与之关联的ReferenceQueue中**

  1. import java.lang.ref.*;
  2. import java.util.*;
  3. import java.util.concurrent.ConcurrentHashMap;
  4. public class TestMain{
  5. public static void main(String[] args) {
  6. ReferenceQueue queue = new ReferenceQueue();
  7. List<Object> list = new ArrayList<>();
  8. PhantomReference<User> phantomReference = new PhantomReference<User>(new User(),queue);
  9. new Thread(
  10. new Runnable() {
  11. @Override
  12. public void run() {
  13. while (true) {
  14. list.add(new byte[1024 * 1024 * 1024 * 5]);
  15. try {
  16. Thread.sleep(500);
  17. }catch (Exception e){
  18. e.printStackTrace();
  19. }
  20. System.out.println(phantomReference.get());
  21. }
  22. }
  23. }).start();
  24. new Thread(new Runnable() {
  25. @Override
  26. public void run() {
  27. while (true) {
  28. //若从引用队列中能拿到虚引用 说明对象已经被回收了
  29. Reference reference = queue.poll();
  30. if (reference != null) {
  31. //若为null 说明已经被GC回收了
  32. System.out.println("虚引用被回收了:" + reference.get());
  33. //输出null
  34. }
  35. }
  36. }
  37. }).start();
  38. }
  39. }

从运行结果可以看到:当发生GC 虚引用就会被回收 并且会把回收的对象放到ReferenceQueue中
虚引用有什么用呢?在NIO中 就运用了虚引用管理堆外内存