Java中的引用類(lèi)型包含四種:強(qiáng)摸航,軟,弱舅桩,虛
強(qiáng)引用
強(qiáng)引用就是我們平時(shí)使用的最多的引用類(lèi)型酱虎,比如:Object obj = new Object();
軟引用
public class SoftReference<T> extends Reference<T> {
}
JSONObject json = new JSONObject();
json.put("key", "json");
SoftReference<JSONObject> reference = new SoftReference<>(json);
reference.get().get("key");
這樣的寫(xiě)法就表面了json是一個(gè)軟引用,軟引用只有在內(nèi)存不足的時(shí)候才會(huì)被回收掉擂涛,所以軟引用很適合做緩沖使用
弱引用
public class WeakReference<T> extends Reference<T> {
public WeakReference(T referent) {
super(referent);
}
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
只有2個(gè)構(gòu)造函數(shù)一個(gè)是沒(méi)有隊(duì)列的读串,一個(gè)是有隊(duì)列的,
隊(duì)列的作用是存放已經(jīng)被回收了的對(duì)象信息撒妈。
JSONObject json = new JSONObject();
json.put("key", "json");
WeakReference<JSONObject> reference1 = new WeakReference<>(json);
reference1.get().get("key");
ReferenceQueue<JSONObject> queue = new ReferenceQueue<>();
WeakReference<JSONObject> reference2 = new WeakReference<>(json, queue);
Reference<? extends com.alibaba.fastjson.JSONObject> ref;
while ((ref = queue.poll()) != null ) {
System.out.println("隊(duì)列中:" + reference2);
}
弱引用主要是用于ThreadLocal中
ThreadLocal:是線(xiàn)程間變量不可見(jiàn)的操作方式恢暖。
ThreadLocal在set值的時(shí)候,會(huì)獲取當(dāng)前上下文中的線(xiàn)程狰右,然后再獲取到當(dāng)前線(xiàn)程的threadLocalMap, 將ThreadLocal設(shè)置為key, 具體對(duì)象設(shè)置為threadLocalMap 的value,
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
}
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
使用ThreadLocal時(shí)需要注意的事情:
1):使用結(jié)束后要及時(shí)remove杰捂,因?yàn)椴籸emove可能會(huì)導(dǎo)致內(nèi)存泄漏:
首先從代碼上我們可以看出來(lái),Entry是繼承了WeakReference<ThreadLocal<?>>, 同時(shí)再給Entry設(shè)值的時(shí)候棋蚌,key是傳入到了super(k)中嫁佳,既:key變成了一個(gè)WeakReference,而value依然是Object的強(qiáng)引用谷暮,所以當(dāng)發(fā)生GC的時(shí)候脱拼,key馬上就被回收了,但是value卻一直存在變成了一種null – value這樣的存儲(chǔ)結(jié)構(gòu)坷备,使得value一直存留在了內(nèi)存中熄浓。
(其實(shí)這個(gè)地方比較繞,剛開(kāi)始的時(shí)候不好理解省撑,因?yàn)橛械娜松涎垡豢窗l(fā)現(xiàn)Entry繼承了WeakReference會(huì)想當(dāng)然的認(rèn)為整個(gè)Entry都是weakReference赌蔑,那一GC的時(shí)候整個(gè)Entry都沒(méi)有了,怎么可能會(huì)存在內(nèi)存泄漏問(wèn)題那竟秫?其實(shí)這個(gè)是2回事情娃惯,第一點(diǎn):WeakReference不存在繼承性;第二點(diǎn):只有被WeakReference引用了的對(duì)象才是弱引用肥败,Entry并沒(méi)有被WeakReference 引用所以Entry, value都是強(qiáng)引用)
2): 線(xiàn)程池不建議使用ThreadLocal,
因?yàn)榫€(xiàn)程池會(huì)復(fù)用線(xiàn)程趾浅,所以當(dāng)我們?cè)诂F(xiàn)場(chǎng)池中使用了ThreadLocal 忘記remove時(shí),線(xiàn)程池再次激活核心線(xiàn)程后會(huì)讀取到上一次的臟數(shù)據(jù)馒稍。
虛引用
虛引用主要是用來(lái)管理堆外內(nèi)存的皿哨,因?yàn)槲覀兊腏VM只能操作自己的堆內(nèi)存,不能操作OS的內(nèi)存纽谒,虛引用的底層是UnSafe類(lèi)(c++)可以直接清理OS的內(nèi)存证膨。
ReferenceQueue<JSONObject> queue1 = new ReferenceQueue<>();
PhantomReference<JSONObject> reference3 = new PhantomReference<>(json, queue);
創(chuàng)建虛引用時(shí)候需要指定一個(gè)隊(duì)列,發(fā)生GC的時(shí)候用于保存被回收后對(duì)象的引用鼓黔。虛引用在對(duì)象被釋放之前央勒,將把它對(duì)應(yīng)的虛引用添加到它關(guān)聯(lián)的引用隊(duì)列中不见,這使得可以在對(duì)象被回收之前采取一些清理工作。