中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

系統線程的實現原理是什么

發布時間:2021-10-25 14:53:15 來源:億速云 閱讀:167 作者:iii 欄目:編程語言

這篇文章主要介紹“系統線程的實現原理是什么”,在日常操作中,相信很多人在系統線程的實現原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”系統線程的實現原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

各種操作系統均提供了線程的實現(內核線程),線程是 CPU 進行工作調度的基本單位
線程是比進程更輕量級的調度執行單位,線程的引入,可以把一個進程的資源分配和執行調度分開,各個線程既可以共享進程資源(內存地址、文件I/O等),又可以獨立調度(線程是CPU調度的基本單位)。而編程語言一般都會提供操作內核線程的 API, Java 也不例外。
操作內核線程的模型主要有如下三種:
  1. 使用內核線程(1:1 模型)

  2. 使用用戶線程(1:N 模型)

  3. 使用用戶線程 + 輕量級進程(LWP)(N:M 模型)

基礎概念復習     

我們先復習下操作系統中的幾個關鍵概念:

  • 內核線程 KLT:內核級線程(Kemel-Level Threads, KLT 也有叫做內核支持的線程),直接由操作系統內核支持,線程創建、銷毀、切換開銷較大
  • 用戶線程 UT:用戶線程(User Thread,UT),建立在用戶空間,系統內核不能感知用戶線程的存在,線程創建、銷毀、切換開銷小
  • 輕量級進程 LWP:           (LWP,Light weight process)用戶級線程和內核級線程之間的中間層,是由操作系統提供給用戶的操作內核線程的接口的實現 。
  • 進程 P:用戶進程 

操作系統的三種線程模型

下面依次介紹三種線程模型:

內核線程模型:

內核線程模型即完全依賴操作系統內核提供的內核線程(Kernel-Level Thread ,KLT)來實現多線程。在此模型下,線程的切換調度由系統內核完成,系統內核負責將多個線程執行的任務映射到各個CPU中去執行。

程序一般不會直接去使用內核線程,而是去使用內核線程的一種高級接口——輕量級進程(Light Weight Process,LWP),輕量級進程就是我們通常意義上所講的線程,由于每個輕量級進程都由一個內核線程支持,因此只有先支持內核線程,才能有輕量級進程。這種輕量級進程與內核線程之間1:1的關系稱為一對一的線程模型。         

系統線程的實現原理是什么


  • 用戶線程模型:

    從廣義上來講,一個線程只要不是內核線程,就可以認為是用戶線程(User Thread,UT),因此,從這個定義上來講,輕量級進程也屬于用戶線程,但輕量級進程的實現始終是建立在內核之上的,許多操作都要進行系統調用,效率會受到限制。

    使用用戶線程的優勢在于不需要系統內核支援,劣勢也在于沒有系統內核的支援,所有的線程操作都需要用戶程序自己處理。線程的創建、切換和調度都是需要考慮的問題,而且由于操作系統只把處理器資源分配到進程,那諸如“阻塞如何處理”、“多處理器系統中如何將線程映射到其他處理器上”這類問題解決起來將會異常困難,甚至不可能完成。

    因而使用用戶線程實現的程序一般都比較復雜,此處所講的“復雜”與“程序自己完成線程操作”,并不限制程序中必須編寫了復雜的實現用戶線程的代碼,使用用戶線程的程序,很多都依賴特定的線程庫來完成基本的線程操作,這些復雜性都封裝在線程庫之中,除了以前在不支持多線程的操作系統中(如DOS)的多線程程序與少數有特殊需求的程序外,現在使用用戶線程的程序越來越少了,Java、Ruby等語言都曾經使用過用戶線程,最終又都放棄使用它


             

系統線程的實現原理是什么


混合線程模型:

線程除了依賴內核線程實現和完全由用戶程序自己實現之外,還有一種將內核線程與用戶線程一起使用的實現方式。在這種混合實現下,既存在用戶線程,也存在輕量級進程。

用戶線程還是完全建立在用戶空間中,因此用戶線程的創建、切換、析構等操作依然廉價,并且可以支持大規模的用戶線程并發。而操作系統提供支持的輕量級進程則作為用戶線程和內核線程之間的橋梁,這樣可以使用內核提供的線程調度功能及處理器映射,并且用戶線程的系統調用要通過輕量級線程來完成,大大降低了整個進程被完全阻塞的風險。

在這種混合模式中,用戶線程與輕量級進程的數量比是不定的,即為N:M的關系。許多UNIX系列的操作系統,如Solaris、HP-UX等都提供了N:M的線程模型實現。

對于Sun JDK來說,它的Windows版與Linux版都是使用一對一的線程模型實現的,一條Java線程就映射到一條輕量級進程之中,因為Windows和Linux系統提供的線程模型就是一對一的。在Solaris平臺中,由于操作系統的線程特性可以同時支持一對一(通過Bound Threads或Alternate Libthread實現)及多對多(通過LWP/Thread Based Synchronization實現)的線程模型,因此在Solaris版的JDK中也對應提供了兩個平臺專有的虛擬機參數:-XX:+UseLWPSynchronization(默認值)和-XX:+UseBoundThreads來明確指定虛擬機使用哪種線程模型。

         

系統線程的實現原理是什么操作系統的線程調度方式           

線程調度是指系統為線程分配處理器使用權的過程

主要的線程調度方式有兩種,分別是 協同式線程調度(Cooperative Threads-Scheduling)和 搶占式線程調度(Preemptive Threads-Scheduling)

協同式調度
如果使用協同式調度的多線程系統,線程的執行時間由線程本身來控制,線程把自己的工作執行完了之后,要主動通知系統切換到另外一個線程上
協同式多線程的最大好處是實現簡單,而且由于線程要把自己的事情干完后才會進行線程切換,切換操作對線程自己是可知的,所以沒有什么線程同步的問題。
Lua語言中的“協同例程”就是這類實現。它的壞處也很明顯:線程執行時間不可控制,甚至如果一個線程編寫有問題,一直不告知系統進行線程切換,那么程序就會一直阻塞在那里。
很久以前的Windows 3.x系統就是使用協同式來實現多進程多任務的,相當不穩定,一個進程堅持不讓出CPU執行時間就可能會導致整個系統崩潰。

搶占式調度

如果使用搶占式調度的多線程系統,那么每個線程將由系統來分配執行時間,線程的切換不由線程本身來決定(在Java中,Thread.yield()可以讓出執行時間,但是要獲取執行時間的話,線程本身是沒有什么辦法的)。

在這種實現線程調度的方式下,線程的執行時間是系統可控的,也不會有一個線程導致整個進程阻塞的問題。

Java使用的線程調度方式就是搶占式調度。在JDK后續版本中有可能會提供協程(Coroutines)方式來進行多任務處理。

與前面所說的Windows 3.x的例子相對,在Windows 9x/NT內核中就是使用搶占式來實現多進程的,當一個進程出了問題,我們還可以使用任務管理器把這個進程“殺掉”,而不至于導致系統崩潰。

線程優先級

雖然Java線程調度是系統自動完成的,但是我們還是可以“建議”系統給某些線程多分配一點執行時間,另外的一些線程則可以少分配一點——這項操作可以通過設置線程優先級來完成。

Java語言一共設置了10個級別的線程優先級(Thread.MIN_PRIORITY至Thread.MAX_PRIORITY),在兩個線程同時處于Ready狀態時,優先級越高的線程越容易被系統選擇執行。

不過,線程優先級并不是太靠譜,原因是Java的線程是通過映射到系統的原生線程上來實現的,所以線程調度最終還是取決于操作系統,雖然現在很多操作系統都提供線程優先級的概念,但是并不見得能與Java線程的優先級一一對應。

如Solaris中有2147483648(232)種優先級,但Windows中就只有7種,比Java線程優先級多的系統還好說,中間留下一點空位就可以了,但比Java線程優先級少的系統,就不得不出現幾個優先級相同的情況了。


系統線程的實現原理是什么

上圖顯示了Java線程優先級與Windows線程優先級之間的對應關系,Windows平臺的JDK中使用了除THREAD_PRIORITY_IDLE之外的其余6種線程優先級。
Java 線程狀態

Java語言定義了5種線程狀態,在任意一個時間點,一個線程只能有且只有其中的一種狀態,這5種狀態分別如下:


系統線程的實現原理是什么


  1. 新建(New):創建后尚未啟動的線程處于這種狀態。


  2. 運行(Runable):Runable包括了操作系統線程狀態中的Running和Ready,也就是處于此狀態的線程有可能正在執行,也有可能正在等待著CPU為它分配執行時間。


  3. 無限期等待(Waiting):處于這種狀態的線程不會被分配CPU執行時間,它們要等待被其他線程顯式地喚醒。


    以下方法會讓線程陷入無限期的等待狀態:沒有設置Timeout參數的Object.wait()方法。沒有設置Timeout參數的Thread.join()方法。LockSupport.park()方法。


  4. 限期等待(Timed Waiting):處于這種狀態的線程也不會被分配CPU執行時間,不過無須等待被其他線程顯式地喚醒,在一定時間之后它們會由系統自動喚醒。

    以下方法會讓線程進入限期等待狀態:Thread.sleep()方法。設置了Timeout參數的Object.wait()方法。設置了Timeout參數的Thread.join()方法。LockSupport.parkNanos()方法。LockSupport.parkUntil()方法。


  5. 阻塞(Blocked):線程被阻塞了,“阻塞狀態”與“等待狀態”的區別是:“阻塞狀態”在等待著獲取到一個排他鎖,這個事件將在另外一個線程放棄這個鎖的時候發生;而“等待狀態”則是在等待一段時間,或者喚醒動作的發生。在程序等待進入同步區域的時候,線程將進入這種狀態。


  6. 結束(Terminated):已終止線程的線程狀態,線程已經結束執行。

Java 多線程實現          

實現1:繼承Thread類

// 繼承 Threadpublic class MyThread extends Thread {    @Override    public void run() {        System.out.println("MyThread run...");    }}

實現2:實現 Runnable 接口

public class MyRunnable implements Runnable {    @Override    public void run() {        System.out.println("MyRunnable run...");    }}
       

實現3:實現 Callable 接口,使用 FutureTask 獲取異步返回值

  public static void main(String[] args) throws ExecutionException, InterruptedException {    class MyCallable implements Callable<String> {      @Override      public String call() throws Exception {        return "MyCallable";      }    }    FutureTask<String> task = new FutureTask<>(new MyCallable());    Thread c = new Thread(task);    c.start();    System.out.println(task.get());  }


實現4:JDK8以上版本使用 CompletableFuture 進行異步計算。

在Java8中,提供了非常強大的Future的擴展功能,可以幫助我們簡化異步編程的復雜性,并且提供了函數式編程的能力,可以通過回調的方式處理計算結果,也提供了轉換和組合 CompletableFuture 的方法。

public class CompletableFutureTest {  public static void main(String[] args) {    ExecutorService threadPool = Executors.newFixedThreadPool(2);    // JDK1.8 提供的 CompletableFuture    CompletableFuture<String> futureTask = CompletableFuture.supplyAsync(new Supplier<String>() {      @Override      public String get() {        System.out.println("task start");        try {          Thread.sleep(10000);        } catch (Exception e) {          e.printStackTrace();          return "execute failure";        }        System.out.println("task end");        return "execute success";      }    }, threadPool);    // 異步獲取 futureTask 的執行結果,此處代碼可以跟其他流程代碼放在一起    futureTask.thenAccept(e-> System.out.println("future task result:" + e));    System.out.println("main thread end");  }}
輸出結果:task startmain thread endtask endfuture task result:execute success


實現5:使用線程池,ThreadPoolExecutor 類

public ThreadPoolExecutor(int corePoolSize,                          int maximumPoolSize,                          long keepAliveTime,                          TimeUnit unit,                          BlockingQueue<Runnable> workQueue,                          ThreadFactory threadFactory) {        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);}<T> Future<T> submit(Callable<T> task);Future<?> submit(Runnable task);

到此,關于“系統線程的實現原理是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

崇文区| 普洱| 聂拉木县| 盐边县| 自贡市| 望江县| 上栗县| 普陀区| 大兴区| 东明县| 哈尔滨市| 苏尼特左旗| 武乡县| 图木舒克市| 泸西县| 阿拉善右旗| 东丽区| 东台市| 文山县| 阳曲县| 梅河口市| 合山市| 合江县| 日喀则市| 西峡县| 赤水市| 碌曲县| 乐山市| 思南县| 京山县| 建湖县| 商都县| 西盟| 广东省| 延庆县| 景宁| 蒙自县| 周宁县| 库尔勒市| 汤阴县| 宽城|