Java-引用类型

Java-引用类型

四种引用类型(强引用、软引用、弱引用、虚引用)在Java中具有不同的使用场景,可以根据程序的需求和内存管理的要求来选择适当的引用类型。

1. 强引用(Strong Reference):

使用场景:

  • 在绝大多数情况下,我们使用的都是强引用。
  • 当一个对象具有强引用时,垃圾回收器不会回收该对象,即使内存不足时,也不会回收具有强引用的对象。

示例:

Object obj = new Object(); // 强引用

2. 软引用(Soft Reference):

使用场景:

  • 适用于对内存敏感的缓存场景,当内存不足时,可以回收软引用关联的对象,以释放内存。
  • 常用于缓存中,当内存紧张时,垃圾回收器会尽量保留软引用关联的对象,但不保证绝对保留。

示例:

import java.lang.ref.SoftReference;

Object obj = new Object();
SoftReference<Object> softRef = new SoftReference<>(obj);
obj = null; // 取消强引用

3. 弱引用(Weak Reference):

使用场景:

  • 适用于临时性对象的缓存,例如缓存中的对象可以很快被重新计算或重建。
  • 主要用于避免内存泄漏,当对象不再被强引用时,会被垃圾回收器快速回收。

示例:

import java.lang.ref.WeakReference;

Object obj = new Object();
WeakReference<Object> weakRef = new WeakReference<>(obj);
obj = null; // 取消强引用

4. 虚引用(Phantom Reference):

使用场景:

  • 主要用于对象被垃圾回收时收到通知或执行某些清理操作的场景。
  • 通常与引用队列(ReferenceQueue)一起使用,当虚引用关联的对象被垃圾回收时,虚引用会被放入引用队列中,可以在队列中获取通知。

示例:

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

Object obj = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(obj, referenceQueue);
obj = null; // 取消强引用


//下面是一个简单的示例,演示了如何使用 PhantomReference 和 ReferenceQueue 来实现在对象被垃圾回收时收到通知:

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

class MyObject {
    // 一些对象的状态和行为
}

public class ObjectCleanupExample {

    public static void main(String[] args) {
        MyObject myObject = new MyObject();
        ReferenceQueue<MyObject> referenceQueue = new ReferenceQueue<>();
        PhantomReference<MyObject> phantomReference = new PhantomReference<>(myObject, referenceQueue);

        // 此时 myObject 还有强引用
        myObject = null;

        // 在某个时刻,垃圾回收器会回收 myObject 对象,并将 phantomReference 放入 referenceQueue
        System.gc(); // 这里只是建议垃圾回收,不能保证立即执行
        try {
            // 等待垃圾回收器通知,remove会让当前线程阻塞,直到其中一个对象可用或给定的超时期到期
            PhantomReference<MyObject> clearedRef = (PhantomReference<MyObject>) referenceQueue.remove();
            System.out.println("Object has been garbage collected: " + clearedRef.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

总体来说,选择引用类型应该根据具体的需求和对内存管理的要求。强引用适用于绝大多数场景,而软引用、弱引用、虚引用则可以用于一些特定的场景,如缓存、内存敏感的情况或者需要在对象被回收时执行特定操作的情况。

小问题:ThreadLocalMap.Entry为什么使用弱引用,而不是软引用?

ThreadLocalMap​中使用弱引用(WeakReference​)而不是软引用(SoftReference​)的主要原因是避免潜在的内存泄漏问题。

ThreadLocalMap​ 是 ThreadLocal​ 的内部实现,它通过使用弱引用来关联键(ThreadLocal​对象)和值,确保在线程的生命周期结束后,对应的键值对可以被垃圾回收。

如果使用软引用,由于软引用的特性是在内存不足时才会被回收,可能导致即使线程结束,ThreadLocal​ 对象仍然被保留,对应的值也不会被及时释放。这样可能导致内存泄漏,因为线程已经结束,但相关的资源无法被释放。

弱引用相比软引用更加“弱”,只要没有强引用指向 ThreadLocal​ 对象,就有可能被垃圾回收。这确保了在不再需要时能够及时释放与 ThreadLocal​ 相关的资源,从而避免了潜在的内存泄漏问题。

总体而言,选择弱引用而不是软引用是为了保证对应资源在合适的时机能够被及时回收,以防止内存泄漏。这是ThreadLocalMap​在设计上的权衡考虑。

posted @ 2023-12-08 10:59  安浩阳  阅读(30)  评论(0)    收藏  举报