Java四種引用類型

Java四種引用類型

在java中,類型就分爲兩種,基本類型和引用類型或自定義類型。java

引用類型又分爲四種:緩存

  1. 強引用 StrongReference性能優化

  2. 軟引用 SoftReferenceelasticsearch

  3. 若引用 WeakReferenceide

  4. 虛引用 PhantomReference性能

劃分這些類型的目的是:是爲了更靈活的管理對象的生命週期,讓垃圾器在最合適的時間適合回收對象,常見使用的場景是在緩存的實現,好比elasticsearch在載入數據到緩存時,能夠選擇SoftReference做爲緩存的生命週期,在對象池組件common-pool中也利用到SoftReference管理對象池的對象生命週期。雖然,咱們在實際業務中不多有用到這些知識,可是很有必要了解到這些,去幫助咱們去作些程序性能優化。優化

強引用

強引用就是直接引用對象好比下面這樣,咱們在編寫程序時,用到的大多都是強引用this

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

強引用對象,當垃圾回收進行時,不會被回收,及時經過b1 = null;釋放引用,在資源充足時,也不會被垃圾回收馬上回收。若是內存吃緊,Java虛擬機會拋出OutOfMemoryError錯誤,使程序異常終止,不會靠隨意回收具備強引用的對象來解決內存不足的問題。code

軟引用

SoftReference<StringBuffer> softReference = new SoftReference<StringBuffer>(new StringBuffer("hello world"));
System.gc();
System.out.print(softReference.get()); // 只有當內存吃緊時,發生gc後,會報Exception in thread "main" java.lang.NullPointerException,

軟引用的生命週期會比強引用弱點,在內存空間足夠時,垃圾回收器就不會回收它;若是內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠被程序使用。軟引用可用來實現內存敏感的高速緩存。
它也常常和ReferenceQueue配合使用,若是gc在回收掉引用對象後,會把保存引用對象的softReference送入隊列,這時能夠經過下面這行代碼判斷是否被回收。對象

// 建立softReference並提供給註冊隊列
ReferenceQueue<StringBuffer> referenceQueue = new ReferenceQueue<StringBuffer>();
SoftReference<StringBuffer> softReference = new SoftReference<StringBuffer>(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<T> ref = new PooledSoftReference<T>(
            new SoftReference<T>(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<T> 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<StringBuffer> weakReference = new WeakReference<StringBuffer>(new StringBuffer("hello world"));
WeakReference<StringBuffer> weakReference2 = new WeakReference<StringBuffer>(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<StringBuffer> stringBufferReferenceQueue = new ReferenceQueue<StringBuffer>();
PhantomReference<StringBuffer> phantomReference = new PhantomReference<StringBuffer>(new StringBuffer("hello world"), stringBufferReferenceQueue);
System.out.print(phantomReference.get());Exception in thread "main" java.lang.NullPointerException

虛引用,不顧是否被垃圾回收,都不能夠拿到真正的引用對象。通常用法是
程序能夠經過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。若是程序發現某個虛引用已經被加入到引用隊列,那麼就能夠在所引用的對象的內存被回收以前採起必要的行動。

具體Demo代碼請參照:ReferenceDemo

相關文章
相關標籤/搜索