死磕 java線程系列之線程模型

問題

(1)線程有哪些類型?python

(2)線程模型有哪些?編程

(3)各語言是怎麼實現本身的線程模型的?多線程

簡介

在Java中,咱們平時所說的併發編程、多線程、共享資源等概念都是與線程相關的,這裏所說的線程實際上應該叫做「用戶線程」,而對應到操做系統,還有另一種線程叫做「內核線程」。併發

用戶線程位於內核之上,它的管理無需內核支持;而內核線程由操做系統來直接支持與管理。幾乎全部的現代操做系統,包括 Windows、Linux、Mac OS X 和 Solaris,都支持內核線程。ide

最終,用戶線程和內核線程之間必然存在某種關係,本章咱們一塊兒來學習下創建這種關係常見的三種方法:多對一模型、一對一模型和多對多模型。高併發

多對一模型

thread model

多對一線程模型,又叫做用戶級線程模型,即多個用戶線程對應到同一個內核線程上,線程的建立、調度、同步的全部細節所有由進程的用戶空間線程庫來處理。性能

優勢:學習

  • 用戶線程的不少操做對內核來講都是透明的,不須要用戶態和內核態的頻繁切換,使線程的建立、調度、同步等很是快;

缺點:操作系統

  • 因爲多個用戶線程對應到同一個內核線程,若是其中一個用戶線程阻塞,那麼該其餘用戶線程也沒法執行;線程

  • 內核並不知道用戶態有哪些線程,沒法像內核線程同樣實現較完整的調度、優先級等;

許多語言實現的協程庫基本上都屬於這種方式,好比python的gevent。

一對一模型

thread model

一對一模型,又叫做內核級線程模型,即一個用戶線程對應一個內核線程,內核負責每一個線程的調度,能夠調度到其餘處理器上面。

優勢:

  • 實現簡單,本文由公從號「彤哥讀源碼」原創;

缺點:

  • 對用戶線程的大部分操做都會映射到內核線程上,引發用戶態和內核態的頻繁切換;

  • 內核爲每一個線程都映射調度實體,若是系統出現大量線程,會對系統性能有影響;

Java使用的就是一對一線程模型,因此在Java中啓一個線程要謹慎。

多對多模型

thread model

多對多模型,又叫做兩級線程模型,它是博採衆長以後的產物,充分吸取前兩種線程模型的優勢且儘可能規避它們的缺點。

在此模型下,用戶線程與內核線程是多對多(m : n,一般m>=n)的映射模型。

首先,區別於多對一模型,多對多模型中的一個進程能夠與多個內核線程關聯,因而進程內的多個用戶線程能夠綁定不一樣的內核線程,這點和一對一模型類似;

其次,又區別於一對一模型,它的進程裏的全部用戶線程並不與內核線程一一綁定,而是能夠動態綁定內核線程, 當某個內核線程由於其綁定的用戶線程的阻塞操做被內核調度讓出CPU時,其關聯的進程中其他用戶線程能夠從新與其餘內核線程綁定運行。

因此,多對多模型既不是多對一模型那種徹底靠本身調度的也不是一對一模型徹底靠操做系統調度的,而是中間態(自身調度與系統調度協同工做),由於這種模型的高度複雜性,操做系統內核開發者通常不會使用,因此更多時候是做爲第三方庫的形式出現。

優勢:

  • 兼具多對一模型的輕量;

  • 因爲對應了多個內核線程,則一個用戶線程阻塞時,其餘用戶線程仍然能夠執行;

  • 因爲對應了多個內核線程,則能夠實現較完整的調度、優先級等;

缺點:

  • 實現複雜,本文由公從號「彤哥讀源碼」原創;

Go語言中的goroutine調度器就是採用的這種實現方案,在Go語言中一個進程能夠啓動成千上萬個goroutine,這也是其出道以來就自帶「高併發」光環的重要緣由。

後面講到Java中的ForkJoinPool的時候,咱們會拿Go語言的PMG線程模型來對比講解。

總結

(1)線程分爲用戶線程和內核線程;

(2)線程模型有多對一模型、一對一模型、多對多模型;

(3)操做系統通常只實現到一對一模型;

(4)Java使用的是一對一線程模型,因此它的一個線程對應於一個內核線程,調度徹底交給操做系統來處理;

(5)Go語言使用的是多對多線程模型,這也是其高併發的緣由,它的線程模型與Java中的ForkJoinPool很是相似;

(6)python的gevent使用的是多對一線程模型;

彩蛋

你所學過的語言都是使用的什麼線程模型呢?

相關文章
相關標籤/搜索