Java內核級線程測試&內核級線程與用戶級線程區別

用戶級線程

有關線程管理的所有工作都由應用程序完成,內核意識不到線程的存在. 應用程序可以通過使用線程庫設計成多線程程序. 通常,應用程序從單線程起始,在該線程中開始運行,在其運行的任何時刻,可以通過調用線程庫中的派生例程創建一個在相同進程中運行的新線程。

用戶級線程僅存在於用戶空間中,此類線程的創建、撤銷、線程之間的同步與通信功能,都無須利用系統調用來實現。用戶進程利用線程庫來控制用戶線程。由於線程在進程內切換的規則遠比進程調度和切換的規則簡單,不需要用戶態/核心態切換,所以切換速度快。由於這裏的處理器時間片分配是以進程爲基本單位,所以每個線程執行的時間相對減少爲了在操作系統中加入線程支持,採用了在用戶空間增加運行庫來實現線程,這些運行庫被稱爲“線程包”,用戶線程是不能被操作系統所感知的。用戶線程多見於一些歷史悠久的操作系統,例如Unix操作系統

用戶級線程駐留在用戶空間或模式。運行時庫管理這些線程,它也位於用戶空間。它們對於操作系統是不可見的,因此無法被調度到處理器內核。每個線程並不具有自身的線程上下文。因此,就線程的同時執行而言,任意給定時刻每個進程只能夠有一個線程在運行,而且只有一個處理器內核會被分配給該進程。對於一個進程,可能有成千上萬個用戶級線程,但是它們對系統資源沒有影響。運行時庫調度並分派這些線程。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tFsyU0IC-1588062428559)(leanote://file/getImage?fileId=5ea7e307e32aa811e1000001)]

用戶線程的優點

  • 可以在不支持線程的操作系統中實現。

  • 創建和銷燬線程、線程切換代價等線程管理的代價比內核線程少得多, 因爲保存線程狀態的過程和調用程序都只是本地過程

  • 允許每個進程定製自己的調度算法,線程管理比較靈活。這就是必須自己寫管理程序,與內核線程的區別

  • 線程能夠利用的表空間和堆棧空間比內核級線程多

  • 不需要陷阱,不需要上下文切換,也不需要對內存高速緩存進行刷新,使得線程調用非常快捷

線程的調度不需要內核直接參與,控制簡單。

用戶線程的缺點

  • 線程發生I/O或頁面故障引起的阻塞時,如果調用阻塞系統調用則內核由於不知道有多線程的存在,而會阻塞整個進程從而阻塞所有線程, 因此同一進程中只能同時有一個線程在運行

  • 頁面失效也會產生類似的問題。

  • 一個單獨的進程內部,沒有時鐘中斷,所以不可能用輪轉調度的方式調度線程

  • 資源調度按照進程進行,多個處理機下,同一個進程中的線程只能在同一個處理機下分時複用

補充
在用戶級線程中,每個進程裏的線程表由運行時系統管理。當一個線程轉換到就緒狀態或阻塞狀態時,在該線程表中存放重新啓動該線程所需的信息,與內核在進程表中存放的進程的信息完全一樣

內核級線程

內核線程建立和銷燬都是由操作系統負責、通過系統調用完成的。在內核的支持下運行,無論是用戶進程的線程,或者是系統進程的線程,他們的創建、撤銷、切換都是依靠內核實現的。

線程管理的所有工作由內核完成,應用程序沒有進行線程管理的代碼,只有一個到內核級線程的編程接口. 內核爲進程及其內部的每個線程維護上下文信息,調度也是在內核基於線程架構的基礎上完成

內核線程駐留在內核空間,它們是內核對象。有了內核線程,每個用戶線程被映射或綁定到一個內核線程。用戶線程在其生命期內都會綁定到該內核線程。一旦用戶線程終止,兩個線程都將離開系統。這被稱作”一對一”線程映射,

線程的創建、撤銷和切換等,都需要內核直接實現,即內核瞭解每一個作爲可調度實體的線程

這些線程可以在全系統內進行資源的競爭

內核空間內爲每一個內核支持線程設置了一個線程控制塊(TCB),內核根據該控制塊,感知線程的存在,並進行控制

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yJ7uJVNT-1588062428565)(leanote://file/getImage?fileId=5ea7e3f1e32aa811e1000002)]

內核線程的優點:

  • 多處理器系統中,內核能夠並行執行同一進程內的多個線程

  • 如果進程中的一個線程被阻塞,能夠切換同一進程內的其他線程繼續執行(用戶級線程的一個缺點)

  • 所有能夠阻塞線程的調用都以系統調用的形式實現,代價可觀

  • 當一個線程阻塞時,內核根據選擇可以運行另一個進程的線程,而用戶空間實現的線程中,運行時系統始終運行自己進程中的線程

  • 信號是發給進程而不是線程的,當一個信號到達時,應該由哪一個線程處理它?線程可以“註冊”它們感興趣的信號

Java線程類型

測試:

package com.liaojl.test.concurrent;

import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * @author LiaoJL
 * @description TODO
 * @file Test4.java
 * @email [email protected]
 * @date 2020/4/28 15:09
 */
public class Test4 {
    private static final Logger log = LoggerFactory.getLogger(Test4.class);

    private ThreadPoolExecutor threadPoolExecutorLink = new ThreadPoolExecutor(
            1000,
            10002,
            2, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    private ThreadPoolExecutor threadPoolExecutor = null;

    @Before
    public void before() {
        threadPoolExecutor = threadPoolExecutorLink;
    }

    @Test
    public void threadPoolExecutor1() throws InterruptedException {
        for (int i = 0; i < 100000; i++) {
            threadPoolExecutor.execute(() -> {
                log.info("線程:{}", Thread.currentThread().getId());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    log.error(e.getMessage(), e);
                }
            });
        }
        Thread.sleep(10000);
    }
}

測試前:
在這裏插入圖片描述

測試中:
在這裏插入圖片描述

線程可以被操作系統感知,故Java的線程類型爲內核級

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