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<Object> weakObj1 = new WeakReference<Object>(obj1);
WeakReference<Object> weakObj2 = new WeakReference<Object>(new Object());
//主動回收
System.gc();
System.out.println(weakObj1.get()); // 非null
System.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<K,V> {
//LRU所允許的最大緩存量
private final int size;
private final Map<K,V> eden;
private final Map<K,V> 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<Object>
,也就是其包裹着虛引用對象,分析其構造函數,
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;
}
}
}
複制
參考文章
了解Java中的弱引用