【多線程併發編程】八 線程的禮讓和守護線程

程序猿學社的GitHub,歡迎Star
https://github.com/ITfqyd/cxyxs
本文已記錄到github,形成對應專題。

前言

上一篇文章,我們瞭解線程的優先級,這次,我們一起來學習一下線程的禮讓和守護。聽起來是不是一臉懵逼,別急,我們來一一瞭解。

1.線程的禮讓

什麼是線程的禮讓

線程的禮讓,就是讓出自己搶到的執行權,也就是我們所說的時間片,讓出執行權,並不意味着,該線程不參與下輪的爭搶勒。

yield方法

打開Thread類,通過alt+7(idea版本),我們可以快速找到該方法。

  public static native void yield();
  • 我們可以看到有一個關鍵字native,但是,我們找不到具體的方法,說明他是通過C或者C++實現的,使用native關鍵字說明這個方法是原生函數。
  • 如果用使用過java調用dll文件的社友,就會覺得這個很熟悉,熟悉的味道。

爲什麼不通過java實現?

  • 我們查看jdk源碼,可以發現有不少方法被修飾爲native,Java 1.1開始就引入了JNI,如果我們想與操作系統進行交互,就需要通過JNI與操作系統進行交互。

yield實戰

package com.cxyxs.thread.eight;

/**
 * Description:轉發請註明來源  程序猿學社 - https://ithub.blog.csdn.net/
 * Author: 程序猿學社
 * Date:  2020/2/26 19:05
 * Modified By:
 */
public class YieldThread  implements  Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+",早上打卡上班");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+",晚上打卡下班");
    }

    public static void main(String[] args) {
        YieldThread yieldThread = new YieldThread();
        Thread t = new Thread(yieldThread,"程序猿學社");
        Thread t1 = new Thread(yieldThread,"隔壁老王");
        t.start();
        t1.start();
    }
}

交替運行
在這裏插入圖片描述
先運行玩完一個線程,再運行另外一個線程。在這裏插入圖片描述

  • 通過多次測試,我們可以得出一個結論。調用yield方法會使線程讓出當前的執行權,但是,並不代表,他不參與下輪的時間片的爭搶。
  • 調用該方法會使線程從運行狀態切換到就緒狀態。
  • 下一次再拿到時間片後,會繼續從調用yield方法後的下一句代碼開始運行。
    在這裏插入圖片描述

2.守護線程

守護線程的概念

java線程可以劃分爲兩種:

  • 用戶線程(我們自定義的線程)
  • 守護線程(就是爲他人服務的,當java進程中沒有用戶線程時,他就會自動銷燬),我們常見的有垃圾回收線程。
    案例:
    守護線程可以理解爲玄幻小說裏面的寵物,跟主人簽訂了主從協議,主人身死,自己也會死掉。

守護線程場景

  • 我們的垃圾回收線程就是一個守護線程,爲什麼要設計成守護線程,他就是爲了保證,所有的用戶線程都退出後,直接不產生新的垃圾後,作爲我們java的雷鋒同志垃圾回收線程,纔會默默地消失。
    在這裏插入圖片描述
  • 通過查看Timer定時器的源碼,我們可以發現,他竟然可以傳參數設置是否爲守護線程。

代碼實戰

package com.cxyxs.thread.eight;

/**
 * Description:守護線程
 * 轉發請註明來源  程序猿學社 - https://ithub.blog.csdn.net/
 * Author: 程序猿學社
 * Date:  2020/2/27 0:31
 * Modified By:
 */
public class WatchThread implements  Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            try {
                System.out.println("程序猿學社:第"+i+"次打卡");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        WatchThread watchThread = new WatchThread();
        Thread thread = new Thread(watchThread);
        thread.setDaemon(true);  //設置線程爲守護線程
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main線程已結束!");
    }
}

在這裏插入圖片描述

  • 不設置setDaemon,通過Thread源碼,可以發現默認值爲false,也就是說,我們自定義的線程,如果再不手動設置爲true的前提下,自定義的線程都是用戶線程。
  • 通過測試,我們可以發現main線程已經打印結束的情況下,從線程還在運行。一直在不停的打印。
  • main線程是用戶線程,不是守護線程,這裏驗證完畢,有不少社友認爲main線程是守護線程。
    在這裏插入圖片描述
  • setDaemon方法爲true,表示設置爲守護線程。
  • 在沒有用戶線程的情況下,進程會自動退出。其他的守護線程也會自動銷燬。

驗證線程是否爲守護線程

package com.cxyxs.thread.eight;

/**
 * Description:轉發請註明來源  程序猿學社 - https://ithub.blog.csdn.net/
 * Author: 程序猿學社
 * Date:  2020/2/27 1:11
 * Modified By:
 */
public class Demo1 {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+"線程");
        System.out.println(Thread.currentThread().isDaemon());
    }
}

在這裏插入圖片描述

  • 通過這個案例,我們應該知道main線程不是守護線程了把。

總結:實際上,在我們日常的開發過程中,幾乎都不會用到線程的禮讓和守護線程。但是,我們爲什麼需要去了解他。這種問題,就類似於我們學習springboot是否還需要學習springmvc一樣。個人覺得,底層原理還是有學習的必要,這樣你才能知其然知其所以然,而不是永遠停用在使用的階段,這也是我們大部分的開發,工作幾年後,工資一直上不去的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章