资讯专栏INFORMATION COLUMN

Java四种引用类型

chuyao / 2134人阅读

摘要:四种引用类型在中,类型就分为两种,基本类型和引用类型或自定义类型。软引用可用来实现内存敏感的高速缓存。一般用法是程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。

Java四种引用类型

在java中,类型就分为两种,基本类型和引用类型或自定义类型。

引用类型又分为四种:

强引用 StrongReference

软引用 SoftReference

若引用 WeakReference

虚引用 PhantomReference

划分这些类型的目的是:是为了更灵活的管理对象的生命周期,让垃圾器在最合适的时间适合回收对象,常见使用的场景是在缓存的实现,比如elasticsearch在载入数据到缓存时,可以选择SoftReference作为缓存的生命周期,在对象池组件common-pool中也利用到SoftReference管理对象池的对象生命周期。虽然,我们在实际业务中很少有用到这些知识,但是很有必要了解到这些,去帮助我们去做些程序性能优化。

强引用

强引用就是直接引用对象比如下面这样,我们在编写程序时,用到的大多都是强引用

StringBuffer b1 = new StringBuffer("hello world");

强引用对象,当垃圾回收进行时,不会被回收,及时通过b1 = null;释放引用,在资源充足时,也不会被垃圾回收立刻回收。如果内存吃紧,Java虚拟机会抛出OutOfMemoryError错误,使程序异常终止,不会靠随意回收具有强引用的对象来解决内存不足的问题。

软引用
SoftReference softReference = new SoftReference(new StringBuffer("hello world"));
System.gc();
System.out.print(softReference.get()); // 只有当内存吃紧时,发生gc后,会报Exception in thread "main" java.lang.NullPointerException,

软引用的生命周期会比强引用弱点,在内存空间足够时,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
它也经常和ReferenceQueue配合使用,如果gc在回收掉引用对象后,会把保存引用对象的softReference送入队列,这时可以通过下面这行代码判断是否被回收。

// 创建softReference并提供给注册队列
ReferenceQueue referenceQueue = new ReferenceQueue();
SoftReference softReference = new SoftReference(new StringBuffer("hello world"),referenceQueue);

// 判断入队列来判断是否被回收,或直接判断softReference.get() == null
softReference.get() == null || softReference.enqueue()   

另外也可以手动清除这些保存引用对象的reference对象

Reference ref;
while ((ref = referenceQueue.poll()) != null) {
    // poll出即清除,也不必手动清除,等待gc清除
}

使用案列:common-pool2的SoftReferenceObjectPool,用于实现一种可以随着需要而增长的池对象管理,当gc时可以清除空闲的实例。

下面是common-pool2的部分代码,具体可以参照其里面的SoftReferenceObjectPool

@Override
public synchronized void addObject() throws Exception {
    assertOpen();
    if (factory == null) {
        throw new IllegalStateException(
                "Cannot add objects without a factory.");
    }
    T obj = factory.makeObject().getObject();
    createCount++;
    // Create and register with the queue
    PooledSoftReference ref = new PooledSoftReference(
            new SoftReference(obj, refQueue));
    allReferences.add(ref);
    boolean success = true;
    if (!factory.validateObject(ref)) {
        success = false;
    } else {
        factory.passivateObject(ref);
    }
    boolean shouldDestroy = !success;
    if (success) {
        idleReferences.add(ref);
        notifyAll(); // numActive has changed
    }
    if (shouldDestroy) {
        try {
            destroy(ref);
        } catch (Exception e) {
            // ignored
        }
    }
    
    @Override
    public synchronized void returnObject(T obj) throws Exception {
        boolean success = !isClosed();
        final PooledSoftReference ref = findReference(obj);
        if (ref == null) {
            throw new IllegalStateException(
                "Returned object not currently part of this pool");
        }
        if (factory != null) {
            if (!factory.validateObject(ref)) {
                success = false;
            } else {
                try {
                    factory.passivateObject(ref);
                } catch (Exception e) {
                    success = false;
                }
            }
        }
        boolean shouldDestroy = !success;
        numActive--;
        if (success) {
            // Deallocate and add to the idle instance pool
            ref.deallocate();
            idleReferences.add(ref);
        }
        notifyAll(); // numActive has changed
        if (shouldDestroy && factory != null) {
            try {
                destroy(ref);
            } catch (Exception e) {
                // ignored
            }
        }
    }

弱引用
WeakReference weakReference = new WeakReference(new StringBuffer("hello world"));
WeakReference weakReference2 = new WeakReference(new StringBuffer("hello world"));
System.out.print(weakReference.get()); //  hello world
StringBuffer buffer = weakReference2.get();
System.gc();
System.out.print(weakReference.get()); // Exception in thread "main" java.lang.NullPointerException
System.out.print(weakReference2.get()); //  hello world

弱引用会在发生gc时,没有对象在去引用时会被立刻被回收,不管内存是否充裕。

使用案列:WeakHashMap

虚引用
ReferenceQueue stringBufferReferenceQueue = new ReferenceQueue();
PhantomReference phantomReference = new PhantomReference(new StringBuffer("hello world"), stringBufferReferenceQueue);
System.out.print(phantomReference.get());Exception in thread "main" java.lang.NullPointerException

虚引用,不顾是否被垃圾回收,都不可以拿到真正的引用对象。一般用法是
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

具体Demo代码请参照:ReferenceDemo

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64719.html

相关文章

  • Java中的四种引用(强引用、软引用、弱引用、虚引用

    摘要:在之后,对引用的概念进行了扩充,将引用分为强引用软引用弱引用虚引用种,这种引用强度依次逐渐减弱。软引用是用来描述一些还有用但并非必需的对象。虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。 以下内容摘自《深入理解Java虚拟机 JVM高级特性与最佳实践》第2版,强烈推荐没有看过的同学阅读,读完的感觉就是原来学的都是些什么瘠薄东西(╯‵□′)╯︵┴─┴ 在JDK1.2以前,Ja...

    wwolf 评论0 收藏0
  • java当中的四种引用

    摘要:如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为,这样一来的话,在合适的时间就会回收该对象。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。 强引用,软引用,弱引用,虚引用。不同的引用类型主要体现在GC上: △强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryErr...

    peixn 评论0 收藏0
  • Java中的四种引用类型:强引用、软引用、弱引用和虚引用

    摘要:虚引用与软引用和弱引用的一个区别在于虚引用必须和引用队列联合使用。 本文已同步至个人博客liaosis blog 在Java中是由JVM负责内存的分配和回收,这是它的优点(简化编程者的工作,不需要像C语言那样去手动操作内存),但同时也是它的缺点(不够灵活,垃圾回收对于编程者来说是不可控的)。 在JDK1.2以前,如果一个对象不被任何变量引用,则程序无法再次使用这个对象,这个对象最终会...

    makeFoxPlay 评论0 收藏0
  • 深入解析强引用、软引用、弱引用、幻象引用

    摘要:弱引用与软引用最大的区别就是弱引用比软引用的生命周期更短暂。所以对于软引用弱引用之类,垃圾收集器可能会存在二次确认的问题,以确保处于弱引用状态的对象没有改变为强引用。 关于强引用、软引用、弱引用、幻象引用的区别,在一些大公司的面试题中经常出现,可能有些小伙伴觉得这个知识点比较冷门,但其实大家在开发中经常用到,如new一个对象的时候就是强引用的应用。 在java语言中,除了原始数据类型(...

    Bmob 评论0 收藏0

发表评论

0条评论

chuyao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<