第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

守護線程與用戶線程

1. 前言

本節(jié)內(nèi)容主要是對守護線程與用戶線程進行深入的講解,具體內(nèi)容點如下:

  • 了解守護線程與用戶線程的定義及區(qū)別,使我們學(xué)習(xí)本節(jié)內(nèi)容的基礎(chǔ)知識點;
  • 了解守護線程的特點,是我們掌握守護線程的第一步;
  • 掌握守護線程的創(chuàng)建,是本節(jié)內(nèi)容的重點;
  • 通過守護線程與 JVM 的退出實驗,更加深入的理解守護線程的地位以及作用,為本節(jié)內(nèi)容次重點;
  • 了解守護線程的作用及使用場景,為后續(xù)開發(fā)過程中提供守護線程創(chuàng)建的知識基礎(chǔ)。

2. 守護線程與用戶線程的定義及區(qū)別

Java 中的線程分為兩類,分別為 daemon 線程(守護線程〉和 user 線程(用戶線程)。

在 JVM 啟動時會調(diào)用 main 函數(shù), main 函數(shù)所在的線程就是一個用戶線程,其實在 JVM 內(nèi)部同時還啟動了好多守護線程,比如垃圾回收線程。

守護線程定義:所謂守護線程,是指在程序運行的時候在后臺提供一種通用服務(wù)的線程。比如垃圾回收線程就是一個很稱職的守護者,并且這種線程并不屬于程序中不可或缺的部分。

因此,當(dāng)所有的非守護線程結(jié)束時,程序也就終止了,同時會殺死進程中的所有守護線程。反過來說,只要任何非守護線程還在運行,程序就不會終止。

用戶線程定義:某種意義上的主要用戶線程,只要有用戶線程未執(zhí)行完畢,JVM 虛擬機不會退出。

區(qū)別:在本質(zhì)上,用戶線程和守護線程并沒有太大區(qū)別,唯一的區(qū)別就是當(dāng)最后一個非守護線程結(jié)束時,JVM 會正常退出,而不管當(dāng)前是否有守護線程,也就是說守護線程是否結(jié)束并不影響 JVM 的退出。

言外之意,只要有一個用戶線程還沒結(jié)束, 正常情況下 JVM 就不會退出。

3. 守護線程的特點

Java 中的守護線程和 Linux 中的守護進程是有些區(qū)別的,Linux 守護進程是系統(tǒng)級別的,當(dāng)系統(tǒng)退出時,才會終止。

而 Java 中的守護線程是 JVM 級別的,當(dāng) JVM 中無任何用戶進程時,守護進程銷毀,JVM 退出,程序終止??偨Y(jié)來說,Java 守護進程的最主要的特點有:

  • 守護線程是運行在程序后臺的線程;
  • 守護線程創(chuàng)建的線程,依然是守護線程;
  • 守護線程不會影響 JVM 的退出,當(dāng) JVM 只剩余守護線程時,JVM 進行退出;
  • 守護線程在 JVM 退出時,自動銷毀。

4. 守護線程的創(chuàng)建

創(chuàng)建方式:將線程轉(zhuǎn)換為守護線程可以通過調(diào)用 Thread 對象的 setDaemon (true) 方法來實現(xiàn)。

創(chuàng)建細節(jié)

  • thread.setDaemon (true) 必須在 thread.start () 之前設(shè)置,否則會跑出一個 llegalThreadStateException 異常。你不能把正在運行的常規(guī)線程設(shè)置為守護線程;
  • 在 Daemon 線程中產(chǎn)生的新線程也是 Daemon 的;
  • 守護線程應(yīng)該永遠不去訪問固有資源,如文件、數(shù)據(jù)庫,因為它會在任何時候甚至在一個操作的中間發(fā)生中斷。

線程創(chuàng)建代碼示例

public class DemoTest {
    public static void main(String[] args) throws InterruptedException {
        Thread threadOne = new Thread(new Runnable() {
            @Override
            public void run() {
                //代碼執(zhí)行邏輯
            }
        });
        threadOne.setDaemon(true); //設(shè)置threadOne為守護線程
        threadOne. start();
    }
}

5. 守護線程與 JVM 的退出實驗

為了更好的了解守護線程與 JVM 是否退出的關(guān)系,我們首先來設(shè)計一個守護線程正在運行,但用戶線程執(zhí)行完畢導(dǎo)致的 JVM 退出的場景。

場景設(shè)計

  • 創(chuàng)建 1 個線程,線程名為 threadOne;
  • run 方法線程 sleep 1000 毫秒后,進行求和計算,求解 1 + 2 + 3 + … + 100 的值;
  • 將線程 threadOne 設(shè)置為守護線程;
  • 執(zhí)行代碼,最終打印的結(jié)果;
  • 加入 join 方法,強制讓用戶線程等待守護線程 threadOne;
  • 執(zhí)行代碼,最終打印的結(jié)果。

期望結(jié)果

  • 未加入 join 方法之前,threadOne 不能執(zhí)行求和邏輯,無打印輸出,因為 main 函數(shù)線程執(zhí)行完畢后,JVM 退出,守護線程也就隨之死亡,無打印結(jié)果;
  • 加入 join 方法后,可以打印求和結(jié)果,因為 main 函數(shù)線程需要等待 threadOne 線程執(zhí)行完畢后才繼續(xù)向下執(zhí)行,main 函數(shù)執(zhí)行完畢,JVM 退出。

Tips:main 函數(shù)就是一個用戶線程,main 方法執(zhí)行時,只有一個用戶線程,如果 main 函數(shù)執(zhí)行完畢,用戶線程銷毀,JVM 退出,此時不會考慮守護線程是否執(zhí)行完畢,直接退出。

代碼實現(xiàn) - 不加入 join 方法

public class DemoTest {
    public static void main(String[] args){
        Thread threadOne = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int sum = 0;
                for (int i = 1; i  <= 100; i++) {
                    sum = sum + i;
                }
                System.out.println("守護線程,最終求和的值為: " + sum);
            }
        });
        threadOne.setDaemon(true); //設(shè)置threadOne為守護線程
        threadOne. start();
        System.out.println("main 函數(shù)線程執(zhí)行完畢, JVM 退出。");
    }
}

執(zhí)行結(jié)果驗證

main 函數(shù)線程執(zhí)行完畢, JVM 退出。

從結(jié)果上可以看到,JVM 退出了,守護線程還沒來得及執(zhí)行,也就隨著 JVM 的退出而消亡了。

代碼實現(xiàn) - 加入 join 方法

public class DemoTest {
    public static void main(String[] args){
        Thread threadOne = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int sum = 0;
                for (int i = 1; i  <= 100; i++) {
                    sum = sum + i;
                }
                System.out.println("守護線程,最終求和的值為: " + sum);
            }
        });
        threadOne.setDaemon(true); //設(shè)置threadOne為守護線程
        threadOne. start();
        try {
            threadOne.join(); // 加入join 方法
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main 函數(shù)線程執(zhí)行完畢, JVM 退出。");
    }
}

執(zhí)行結(jié)果驗證

守護線程,最終求和的值為: 5050
main 函數(shù)線程執(zhí)行完畢, JVM 退出。

從結(jié)果來看,守護線程不決定 JVM 的退出,除非強制使用 join 方法使用戶線程等待守護線程的執(zhí)行結(jié)果,但是實際的開發(fā)過程中,這樣的操作是不允許的,因為守護線程,默認就是不需要被用戶線程等待的,是服務(wù)于用戶線程的。

6. 守護線程的作用及使用場景

作用:我們以 GC 垃圾回收線程舉例,它就是一個經(jīng)典的守護線程,當(dāng)我們的程序中不再有任何運行的 Thread, 程序就不會再產(chǎn)生垃圾,垃圾回收器也就無事可做,所以當(dāng)垃圾回收線程是 JVM 上僅剩的線程時,垃圾回收線程會自動離開。

它始終在低級別的狀態(tài)中運行,用于實時監(jiān)控和管理系統(tǒng)中的可回收資源。

應(yīng)用場景

  • 為其它線程提供服務(wù)支持的情況,可選用守護線程;
  • 根據(jù)開發(fā)需求,程序結(jié)束時,這個線程必須正常且立刻關(guān)閉,就可以作為守護線程來使用;
  • 如果一個正在執(zhí)行某個操作的線程必須要執(zhí)行完畢后再釋放,否則就會出現(xiàn)不良的后果的話,那么這個線程就不能是守護線程,而是用戶線程;
  • 正常開發(fā)過程中,一般心跳監(jiān)聽,垃圾回收,臨時數(shù)據(jù)清理等通用服務(wù)會選擇守護線程。

7. 小結(jié)

掌握用戶線程和守護線程的區(qū)別點非常重要,在實際的工作開發(fā)中,對一些服務(wù)型,通用型的線程服務(wù)可以根據(jù)需要選擇守護線程進行執(zhí)行,這樣可以減少 JVM 不可退出的現(xiàn)象,并且可以更好地協(xié)調(diào)不同種類的線程之間的協(xié)作,減少守護線程對高優(yōu)先級的用戶線程的資源爭奪,使系統(tǒng)更加的穩(wěn)定。

本節(jié)的重中之重是掌握守護線程的創(chuàng)建以及創(chuàng)建需要注意的事項,了解守護線程與用戶線程的區(qū)別使我們掌握守護線程的前提。