Java中存在四種引用,StrongReference(強引用) 、SoftReferenc(軟引用) 、WeakReferenc(弱引用)、PhantomReference(虛引用).雖然不常用,但是對於理解Java的回收等級還是很有幫助的,一句話來說這些引用只是不同回收等級的一種表現形式.
StrongReference(強引用)
強引用是最經常使用的一種引用,如new操作建立的物件就屬於強引用.如下程式碼,對於強引用要記住無論如何JVM都不會去回收其記憶體.
Object obj = new Object();
SoftReferenc(軟引用)
軟引用是由java.lang.ref.SoftReference所提供的功能,被其所關聯的物件不存在強引用並且此時JVM記憶體不足才會去回收該物件.
個人不知道其用處,做快取的話,現在的企業專案基本不是單體架構所以用處不大,倒是可以做記憶體警告,當物件被回收時則說明系統所需要的記憶體不足,那麼就可以發郵件通知相關人員.
WeakReferenc(弱引用)
弱引用是java.lang.ref包下的WeakReferenc類所提供的包裝功能,對於弱引用JVM會回收僅被弱引用所關聯的物件.也就是說弱引用物件會在一次gc之後被回收,如下程式碼,其中obj1沒被回收,因為其的引用是強引用,但是weakObj1與其關聯是弱引用,因此不屬於被收回物件.weakObj2所關聯的new Object()只有一個弱引用關聯,因此會被回收.
Object obj1 = new Object();
WeakReference weakObj1 = new WeakReference(obj1);
WeakReference weakObj2 = new WeakReference(newObject());//主動回收
System.gc();
System.out.println(weakObj1.get()); // 非
nullSystem.out.println(weakObj2.get()); // null
Java中提供了一個很棒的工具類WeakHashMap,按照註釋所說,該類是一個鍵為弱引用型別的Map,與傳統Map不同的是其鍵會自動刪除釋放掉,因為gc()時會自動釋放,因此很適合做快取這一類的需求,下面程式碼是Tomcat所實現的LRU(最少使用策略)快取演算法的實現,關鍵點在註釋中給出.
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;public final class ConcurrentCache {
//LRU所允許的最大快取量
private final int size;
private final Map eden;
private final Map longterm;
public ConcurrentCache(int size)
{
this.size = size;
//eden是主要快取
this.eden = new ConcurrentHashMap<>(size);
//longterm是實現LRU演算法的關鍵點.
this.longterm = new WeakHashMap<>(size);
} //get是先從eden中取出快取,當不存在時則去longterm中獲取快取,並且此時獲取到的快取說明還在使用,因此會put到eden中(LRU演算法)
public V get(K k) { V v = this.eden.get(k); if (v == null)
{ synchronized (longterm) { v = this.longterm.get(k); }
if (v != null) { this.eden.put(k, v);
}
}
return v;
} //put操作當size大於LRU最大容量時,則把快取都放入到longterm,當this.eden.clear()後使其成為弱引用,那麼LRU的實現則在get方法中體現了出來.
public void put(K k, V v)
{ if (this.eden.size() >= size)
{ synchronized (longterm)
{ this.longterm.putAll(this.eden); } this.eden.clear();
} this.eden.put(k, v);
}}
此方法如果操作時剛好遇到了一次gc,那麼longterm的引用就會丟失,那麼快取就gg了.
PhantomReference(虛引用)
虛引用是由java.lang.ref.PhantomReference所提供的關聯功能,虛引用對其原物件的生命週期毫無影響,其可以算是一種標記,當其所引用物件被回收時其會自動加入到引用佇列中.也就是說你可以通過虛引用得到哪些物件已被回收.具體用法可以分析common.io中的org.apache.commons.io.FileCleaningTracker
該類中有一內部類class Tracker extends PhantomReference,也就是其包裹著虛引用物件,分析其建構函式,marker引數是該具體的虛引用,當marker被回收時,該對應的Track會被加入到引用佇列queue中.
Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue<? super Object> queue) { //marker是具體的虛引用物件 super(marker, queue); this.path = path; this.deleteStrategy = deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy;}
檔案刪除則是該類維護的一個執行緒來進行的操作,既然物件回收後會加入到引用佇列queue,那麼該執行緒要做的功能自然是從引用佇列中獲取到對應的Track,然後執行其刪除策略.
在這個流程中虛引用起到的是跟蹤所包裹物件作用,當包裹的的物件被回收時,這邊會得到一個通知(將其加入到引用佇列).
@Override public void run()
{
// thread exits when exitWhenFinished is true and there are no more tracked objects while (exitWhenFinished == false || trackers.size() > 0) { try { // Wait for a tracker to remove. Tracker tracker = (Tracker) q.remove(); // cannot return null trackers.remove(tracker); if (!tracker.delete()) { deleteFailures.add(tracker.getPath()); } tracker.clear(); } catch (InterruptedException e) { continue; } } }
注:加群要求 學習交流群:450936584
1、想學習JAVA這一門技術, 對JAVA感興趣,想從事JAVA工作的。
2、工作0-5年,感覺自己技術不行,想提升的
3、如果沒有工作經驗,但基礎非常紮實,想提升自己技術的。
4、還有就是想一起交流學習的。
5、小號加群一律不給過,謝謝。
群內每天會分享最新的視訊和資料,可以免費領取學習視訊和資料
轉發此文章請帶上原文連結,否則將追究法律責任!