1. 程式人生 > 實用技巧 >java多執行緒_Java中的引用型別

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