一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java中的引用類型和使用場景詳細

Java中的引用類型和使用場景詳細

2022-02-12 15:28Grey Java教程

這篇文章介紹的是Java中的引用類型和使用場景,主要內容展開Java中的引用類型,有強引用、軟引用 、弱引用、虛引用,需要的朋友可以參考一下

Java中的引用類型有哪幾種?

Java中的引用類型分成 強引用 , 軟引用 , 弱引用 , 虛引用 。

1、強引用

沒有引用指向這個對象,垃圾回收會回收

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package git.snippets.juc;
 
import java.io.IOException;
 
public class NormalRef {
    public static void main(String[] args) throws IOException {
        M m = new M();
        m = null;
        System.gc();
        System.in.read();
    }
    static class M {
        M() {}
        @Override
        protected void finalize() throws Throwable {
            System.out.println("finalized");
        }
    }
}

2、軟引用

當有一個對象被一個軟引用所指向的時候,只有系統(tǒng)內存不夠用的時候,才會被回收,可以用做緩存(比如緩存大圖片)

示例如下代碼:注:執(zhí)行以下方法的時候,需要把VM options設置為 -Xms20M -Xmx20M

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package git.snippets.juc;
 
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.concurrent.TimeUnit;
 
/**
 * heap將裝不下,這時候系統(tǒng)會垃圾回收,先回收一次,如果不夠,會把軟引用干掉
 * 軟引用,適合做緩存
 * 示例需要把Vm options設置為:-Xms20M -Xmx20M
 */
public class SoftRef {
    public static void main(String[] args) throws IOException {
        SoftReference<byte[]> reference = new SoftReference<>(new byte[1024 * 1024 * 10]);
        System.out.println(reference.get());
        System.gc();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(reference.get());
        byte[] bytes = new byte[1024 * 1024 * 10];
        System.out.println(reference.get());
        System.in.read();
    }
}

上述代碼在第一次執(zhí)行 System.out.println(reference.get()) 時候,由于堆的最大最小值都是 20M ,而我們分配的 byte 數(shù)組是 10M ,沒有超過最大堆內存,所以執(zhí)行垃圾回收,軟引用不被回收,后續(xù)又調用了 byte[] bytes = new byte[1024 * 1024 * 10]; 再次分配了 10M 內存,此時堆內存已經(jīng)超過設置的最大值,會進行回收,所以最后一步的 System.out.println(reference.get()); 無法 get 到數(shù)據(jù)。

3、弱引用

只要垃圾回收,就會回收。如果有一個強引用指向弱引用中的這個對象,如果這個強引用消失,這個對象就應該被回收。一般用在容器里面。

代碼示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package git.snippets.juc;
 
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
 
/**
 * 弱引用遭到gc就會回收
 * ThreadLocal應用,緩存應用,WeakHashMap
 */
public class WeakRef {
    public static void main(String[] args) {
        WeakReference<T> reference = new WeakReference<>(new T());
        System.out.println(reference.get());
        System.gc();
        System.out.println(reference.get());
    }
    static class T {
        T() {}
        @Override
        protected void finalize() {
            System.out.println("finalized");
        }
    }
}

如果執(zhí)行了一次 GC reference.get() 獲取到的值即為空。

4、弱引用的使用場景

弱引用的一個典型應用場景就是 ThreadLocal ,以下是 ThreadLocal 的的簡要介紹

set方法:

?
1
2
3
4
5
6
7
8
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

get方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

ThreadLocalMap 是當前線程的一個成員變量,所以,其他線程無法讀取當前線程設置的 ThreadLocal 值。

?
1
ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocal 的主要應用場景

場景一:每個線程需要一個獨享的對象:假設有100個線程都需要用到 SimpleDateFormat 類來處理日期格式,如果共用一個 SimpleDateFormat ,就會出現(xiàn)線程安全問題,導致數(shù)據(jù)出錯,如果加鎖,就會降低性能,此時使用 ThreadLocal ,給每個線程保存一份自己的本地 SimpleDateFormat ,就可以同時保證線程安全和性能需求。

場景二:每個線程內部保存全局變量,避免傳參麻煩:假設一個線程的作用是拿到前端用戶信息,逐層執(zhí)行 Service1 Service2 Service3 Service4 層的業(yè)務邏輯,其中每個業(yè)務層都會用到用戶信息,此時一個解決辦法就是將 User 信息對象作為參數(shù)層層傳遞,但是這樣會導致代碼冗余且不利于維護。此時可以將 User 信息對象放入當前線程的 Threadlocal 中,就變成了全局變量,在每一層業(yè)務層中,需要使用的時候直接從 Threadlocal 中獲取即可。

場景三: Spring 的聲明式事務,數(shù)據(jù)庫連接寫在配置文件,多個方法可以支持一個完整的事務,保證多個方法是用的同一個數(shù)據(jù)庫連接(其實就是放在 ThreadLocal 里面)

了解了 ThreadLocal 簡要介紹以后,我們可以深入理解一下 ThreadLocal 的一個內部原理,前面提到, ThreadLocal 的 set 方法實際上是往當前線程的一個 threadLocals 表中插入一條記錄,而這個表中的記錄都存在一個 Entry 對象中,這個對象有一個key和一個value, key 就是當前線程的 ThreadLocal 對象。

?
1
2
3
4
5
6
7
8
9
static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
 
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

這個 Entry 對象繼承了 WeakReference , 且構造函數(shù)調用了 super(k) , 所以 Entry 中的 key 是通過一個弱引用指向的 ThreadLocal ,所以,我們在主方法中調用

?
1
ThreadLocal<Object> tl = new ThreadLocal<>();

tl 是通過強引用指向這個 ThreadLocal 對象。

當前線程的 threadLocalMap 中的 key 是通過弱引用指向 ThreadLocal 對象,這樣就可以保證,在 tl 指向空以后,這個 ThreadLocal 會被回收,否則,如果 threadLocalMap 中的 key 是強引用指向 ThreadLocal 對象話,這個 ThreadLocal 對象永遠不會被回收。就會導致內存泄漏。

但是,即便 key 用弱引用指向 ThreadLocal 對象, key 值被回收后, Entry 中的 value 值就無法被訪問到了,且 value 是通過強引用關聯(lián),所以,也會導致內存泄漏,所以,每次在 ThreadLocal 中的對象不用了,記得要調用 remove 方法,把對應的 value 也給清掉。

5、虛引用

用于管理堆外內存回收

虛引用關聯(lián)了一個對象,以及一個隊列,只要垃圾回收,虛引用就被回收,一旦虛引用被回收,虛引用會被裝到這個隊列,并會收到一個通知(如果有值入隊列,會得到一個通知)所以,如果想知道虛引用何時被回收,就只需要不斷監(jiān)控這個隊列是否有元素加入進來了。

虛引用里面關聯(lián)的對象用get方法是無法獲取的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.List;
 
// 配置 -Xms20M -Xmx20M
public class PhantomRef {
    private static final List<Object> LIST = new LinkedList<>();
    private static final ReferenceQueue<P> QUEUE = new ReferenceQueue<>();
 
 
    public static void main(String[] args) {
        PhantomReference<P> phantomReference = new PhantomReference<>(new P(), QUEUE);
        new Thread(() -> {
            while (true) {
                LIST.add(new byte[1024 * 1024]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
                System.out.println(phantomReference.get());
            }
        }).start();
 
        new Thread(() -> {
            while (true) {
                Reference<? extends P> poll = QUEUE.poll();
                if (poll != null) {
                    System.out.println("--- 虛引用對象被jvm回收了 ---- " + poll);
                }
            }
        }).start();
 
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
    }
 
    static class P {
        @Override
        protected void finalize() throws Throwable {
            System.out.println("finalized");
        }
    }
}

6、虛引用的應用場景

JDK的 NIO 包中有一個 DirectByteBuffer , 這個 buffer 指向的是堆外內存,所以當這個 buffer 設置為空的時候,Java的垃圾回收無法回收,所以,可以用虛引用來管理這個 buffer ,當我們檢測到這個虛引用被垃圾回收器回收的時候,可以做出相應的處理,去回收堆外內存。

到此這篇關于Java中的引用類型和使用場景詳細的文章就介紹到這了,更多相關Java中的引用類型和使用場景內容請搜索服務器之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/greyzeng/p/15377284.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 精品国内自产拍在线视频 | 亚洲国产精品嫩草影院久久 | 99视频网址 | 色老女人| 免费看一级毛片 | 欧美色图亚洲天堂 | 日本不卡在线视频高清免费 | 性趣用品| 我将她侵犯1~6樱花动漫在线看 | 色天天综合网色鬼综合 | 小寡妇水真多好紧 | 欧美色精品天天在线观看视频 | 日本久久免费大片 | 亚洲琪琪 | 窝窝午夜理伦影院 | 韩国久播影院理论片不卡影院 | 国产精品久久国产三级国电话系列 | 国色天香社区在线视频播放 | 九九九精品视频 | 精品国产国产精2020久久日 | 亚洲欧美天堂综合久久 | 免费欧美日韩 | 大陆日韩欧美 | 精品无码一区在线观看 | 91香蕉国产在线观看人员 | 国产馆在线观看免费的 | 欧美特级午夜一区二区三区 | 99在线精品免费视频九九视 | 911精品国产亚洲日本美国韩国 | 国产精品亚洲精品日韩已满 | 精品国产一区二区三区在线观看 | 变态np虐高h | 91动漫在线观看 | 欧美国产精品久久 | 亚洲视频999| avtt天堂网手机版亚洲 | 国产成人性毛片aaww | 国产农村乱子伦精品视频 | 亚洲六月丁香六月婷婷色伊人 | 3x3x3x短视频在线看 | 天美影视文化传媒mv免费 |