java多執行緒_Java中的引用型別
java中的引用分為4種,分別是:1.強引用;2.軟引用;3.弱引用;4.虛引用。四種引用分別有各自的特點,下面分別通過程式碼對四種類型的引用進行一下測試。
1.強引用
強引用是我們平時最常用的一種引用型別。在物件被引用的時候,不會被gc的垃圾回收器回收。當沒有引用時,堆中物件會被回收。
示範程式碼:
1 /** 2 * 驗證垃圾回收機制類 3 * @author 4 * 5 */ 6 public class M { 7 // 重寫finalize 方法,該方法是Object物件的方法,在物件被回收時執行。 8 // 平時開發不建議在該位置寫程式碼,容易導致OOM問題驗證類9 @Override 10 protected void finalize() { 11 System.out.println("finalize"); 12 } 13 }
1 import java.io.IOException; 2 /** 3 * 強引用 普通的引用 4 * 5 * 棧裡的小m指向堆裡的M物件,這個引用叫做強引用,只有沒有任何引用指向物件的時候,物件才會被垃圾回收器回收 6 * @author Lys 7 * 8 */ 9 public class T01_NormalReference {10 public static void main(String[] args) throws IOException { 11 M m = new M(); 12 m=null; 13 System.gc(); 14 15 System.in.read(); 16 } 17 }
執行結果:
finalize // 說明引用在被置為null 後,在系統gc的時候,物件被垃圾回收器回收了
2.軟引用
只被軟引用所引用的物件,會在jvm記憶體不夠用的時候,被垃圾回收器回收。通過下面的測試程式碼我們可以看出:在m剛被定義的時候,這個時候m還是可以get到值的,然後呼叫系統gc,m物件也沒有被垃圾回收器回收。但是當定義其他物件使記憶體不夠用的時候,該物件就被回收掉了。該引用適用場景:一個比較大的快取物件,經常需要讀取。當系統空間足夠的時候,就將其快取在jvm中,當可用空間不足的時候,就將其回收掉。
示範程式碼:
1 /** 2 * 軟引用 3 * 4 * 軟應用內的物件會隨著空間不夠用而消失,一般應用於快取。 5 * @author Lys 6 * 7 */ 8 public class T02SoftReference { 9 public static void main(String[] args) { 10 SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]); 11 12 System.out.println(m.get()); 13 System.gc(); 14 try { 15 Thread.sleep(500); 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } 19 System.out.println(m.get()); 20 byte[] b = new byte[1024*1024*3]; 21 byte[] b1 = new byte[1024*1024*3]; 22 System.out.println(m.get()); 23 } 24 }
程式碼執行引數:-Xmx20M
程式碼執行結果:
[B@15db9742 [B@15db9742 null // 前兩個列印輸出證明在記憶體足夠的情況下不會被回收,第三個輸出表示,當記憶體不足時,軟引用的物件就被垃圾回收器回收了
3.弱引用
只有弱引用引用的物件在遇到垃圾回收器執行垃圾回收的時候,就會被回收。弱引用的應用場景:ThreadLocal 物件在呼叫set方法,在儲存物件的時候。本身將當前執行緒區域性變數物件作為key值,存入執行緒的ThreadLocalMap中,被set的值作為ThreadLocalMap的value。jdk原始碼如下:
static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
這裡的super(key)建立了一個弱引用,當ThreadLocal 物件在棧中的引用消失後,這個物件就會被垃圾回收器回收,而不必擔心出現記憶體洩漏問題。
示範程式碼:
/** * 驗證垃圾回收機制的物件 * @author * */ public class M { // 重寫finalize 方法,該方法是Object物件的方法,在物件被回收時執行。 // 平時開發不建議在該位置寫程式碼,容易導致OOM問題 @Override protected void finalize() { System.out.println("finalize"); } }驗證物件
import java.lang.ref.WeakReference; import java.util.WeakHashMap; /** * 弱引用 垃圾回收器看到後就回收 ,,就會被回收 * 應用場景:ThreadLocal 解決記憶體洩漏問題 ,但是使用者自己建立的value還存在,所以tl中建立的內容,在tl不用以後,要進行remove操作。 * @author Lys * */ public class T03_WeakRefernce { public static void main(String[] args) { WeakReference<M> m = new WeakReference<M>(new M()); System.out.println(m.get()); System.gc(); System.out.println(m.get()); // ThreadLocal<M> tl = new ThreadLocal<>(); // tl.set(new M()); // tl.remove(); } }
程式碼執行結果:
reference.M@15db9742 null finalize
4.虛引用
虛引用在jvm 中沒有記憶體,用於管理在虛擬機器之外的記憶體。如下圖所示,虛引用必須當我們的虛擬機器需要管理一塊不存在於jvm的記憶體時,需要跟蹤物件的垃圾回收狀態,如果物件被回收了,那麼將該物件的引用放入queue,根據queue中取出的物件去將對應的JVM外面的記憶體進行操作。
示範程式碼:
1 /** 2 * 虛引用 get不到,隨時被回收的物件 3 * 4 * 作用:管理堆外記憶體NIO 5 * @author Lys 6 * 7 */ 8 9 import java.lang.ref.PhantomReference; 10 import java.lang.ref.Reference; 11 import java.lang.ref.ReferenceQueue; 12 import java.util.LinkedList; 13 import java.util.List; 14 15 public class T04_phantomReference { 16 private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>(); 17 public static void main(String[] args) { 18 PhantomReference<M> phantomReference = new PhantomReference<M>(new M(),QUEUE ); 19 20 new Thread(()->{ 21 22 try { 23 System.gc(); 24 Thread.sleep(1000); 25 } catch (Exception e) { 26 e.printStackTrace(); 27 Thread.currentThread().interrupt(); 28 } 29 System.out.println(phantomReference.get()); 30 System.gc(); 31 32 }).start(); 33 34 new Thread(()->{ 35 while (true) { 36 Reference<? extends M> poll = QUEUE.poll(); 37 if (poll!=null) { 38 39 System.out.println("----- 虛引用物件被jvm回收-------"+poll); 40 } 41 } 42 }).start(); 43 } 44 }
執行結果:
finalize null ----- 虛引用物件被jvm回收-------java.lang.ref.PhantomReference@4a140fe5