并發編程系列線程并行學習筆記

      網友投稿 722 2022-05-30

      文章目錄

      一、線程并行相關概念

      同步(Synchronous)和異步(Asynchronous)

      并發(Concurrency)和并行(Parallelism)

      臨界區

      阻塞(Blocking)和非阻塞(Non-Blocking)

      饑餓(Starvation)、死鎖(Deadlock)和活鎖(Livelock)

      并發編程系列之線程并行學習筆記

      二、并行的兩個重要定律

      Amdahi定律

      Gustafson定律

      三、多線程的特性

      原子性

      可見性

      有序性

      一、線程并行相關概念

      同步和異步的本質區別是是否需要等待,比如一個方法在執行,必須等前面一個方法程執行完成,才可以執行,這就是同步。如果不需要等上一個方法執行完成,并行或者并發執行,這就是異步調用。

      并發和并行兩個概念很容易混淆。解釋起來意思也差不多,不過說起來,并行才是真正意義上的并行執行,并發只是線程的交替執行,有可能存在串行的情況。

      在單核CPU的系統,線程只能是并發的,而不能支持并行,并行執行只能存在與多核CPU的系統。

      臨界區,可以理解為公共的資源或者說共享數據。臨界區具有保護性,也就是說,只能一個線程占用臨界區,一旦一個線程占了臨界區,另外一個線程是不予許再占用的,必須等線程釋放了才行。

      阻塞是線程的一種比較嚴重的情況,從前面我們知道了臨界區只能允許一個線程占用,假如一個線程因為執行時間過長,占用了臨界區,不掛起,其它想要占用臨界區的線程只能等待,這種情況就容易造成線程阻塞。非阻塞的話就相反了,指所有線程都正常執行,不會出現線程占臨界區不掛起的情況。

      饑餓,有些情況可能是一個線程優先級太低了,每次都被其它線程占用了,導致改線程一種不能占用臨界區。也有一些情況是上一個線程執行時間太長了,一直沒釋放,導致其它線程都不能占用臨界區,這也是造成線程饑餓。

      死鎖有可能是因為線程死循環調用等等情況造成的,一旦出現這種情況估計就得人工排查了。

      活鎖,解釋一下,一般就是這樣的情況,因為線程互相掛起臨界區,給其它線程用,互相“謙讓”,導致資源在兩個或者幾個線程之間跳到,這種情況就是活鎖。

      二、并行的兩個重要定律

      Amdahi定律定義了串行系統并行化后的加速比公式。

      加速比定義:加速比 = 優化前系統耗時 / 優化后系統耗時

      加速比越高,說明優化越明顯。簡單介紹一下Amdahi定律公式的推導。

      優化后耗時T_n=T1(F+1/n(1-F)),其中T1表示優化前耗時,F表示串行比例,(1-F)表示并行比例,下標n就是處理器的個數。

      導入加速比公式,也就是T1/T_n,也就是1/(F + 1/n(1-F)),公式只是進行簡單介紹。

      從公式可以看出,加速比是和串行比例F成反比的,從公式可以看出增加cpu的個數僅僅是一種提供加速比的方法,增加cpu個數的同時,還可以提供降低串行比例來做,也就是串行比例F越低,加速比也就越高

      Custafson公式也是并行的一個比較重要的公式,現在介紹一下Custafson公式的推導。

      定義一下串行執行時間為a,并行執行時間為b。即單核CPU情況,執行時間為a+b總執行時間為a+nb,n表示CPU個數。

      //定義串行比例

      F=a/(a+b)

      //得到加速比

      s(n)=a+nb/a+b=a/a+b + nb/a+b = F + n*(b-a+a)/a+b = F + n(1-F)

      從公式可以看出,如果串行比例足夠小的情況,加速比其實就是約等于處理器個數,也就是說通過加多CPU的個數就能提高加速比。

      兩個公式看起來似乎有點矛盾,其實不然,兩個公式只是從不同角度分析問題。Amdahi是說在串行比例一定時,通過加CPU的方法是有上限的,通過降低串行比例同時增加cpu個數可以提高加速比。Custafson是說在串行比較趨于很小的情況,從公式可以看出,加cpu就可以提高加速比

      三、多線程的特性

      因為多線程環境的數據不一致性和安全性,所以就需要一些規則類控制,Java的內存模型JMM就規范了多線程有效正確的執行,而JMM也正是圍繞多線程的原子性、可見性、有序性進行的,所以本博客介紹一些多線程的原子性、可見性和有序性

      對于單線程來說,確實是具有原子性的,比如一個int變量,改變一下值,去讀取的時候是那個值,這是很正常的,我們去系統運行,也是這樣的,因為我們的操作系統大部分是32位和64位的,int類型4個字節,也就是32位,不過可以試試long類型的數值,long類型是8個字節,也就是64位,如果兩個線程都對其進行讀寫呢?在多線程環境,一個線程改變了long類型的值,然后再去讀取,獲取到的值就不一定是剛才改變的值了,因為你的系統可能是32位的,而long類型是64位的,如果兩個線程都對long類型進行讀寫,就會出現這種情況。

      對于可見性又應該怎么理解?首先說一下對于單線程來說,是并不存在可見性的,可見性是針對多線程來說的,比如,一個線程進行了改變,另外一個線程是否知道這個線程做了改變,這個就是可見性。舉個例子,變量a是共享變量,一個cpu1上的變量a做了緩存優化,將變量a放在了緩存里,這時,另外一個cpu2上線程對變量a做了改變,這個操作對于cpu1上的線程是不可見的,因為cpu1已經做了緩存,所以cpu1上的線程就從緩存讀取變量a了,發現和cpu2上讀取的值并不一致。

      對于單線程來說,一個線程的代碼執行是按照先后順序的,這樣說是沒錯的,但是在多線程環境可不一定了。因為在多線程環境可能發生指令的重排。也就是說多線程環境,代碼執行是不一定具有有序性的。

      既然無序性是重排導致的,那么是所有的指令都會重排的?當然不是。重排按照:Happen-Before規則。

      列舉一下:

      引用葛一鳴/郭超/. 實戰Java高并發程序設計 (597-601).

      程 序 順 序 原 則: 一 個 線 程 內 保 證 語 義 的 串 行

      性 volatile 規 則: volatile 變 量 的 寫, 先 發 生 于 讀, 這 保 證 了 volatile 變 量 的 可 見 性

      鎖 規 則: 解 鎖( unlock) 必 然 發 生 在 隨 后 的 加 鎖( lock) 前

      傳 遞 性: A 先 于 B, B 先 于 C, 那 么 A 必 然 先 于 C

      線 程 的 start() 方 法 先 于 它 的 每 一 個 動 作

      線 程 的 所 有 操 作 先 于 線 程 的 終 結( Thread.join())

      線 程 的 中 斷( interrupt()) 先 于 被 中 斷 線 程 的 代 碼

      對 象 的 構 造 函 數 執 行、 結 束 先 于 finalize() 方 法

      任務調度 多線程

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:多模態學習綜述
      下一篇:容器-基于Docker構建Kubernetes集群
      相關文章
      亚洲美女视频免费| 亚洲中文字幕一区精品自拍| 99999久久久久久亚洲| 久久亚洲AV成人无码国产| 亚洲人成精品久久久久| 国产成人综合亚洲亚洲国产第一页| 亚洲AV无码一区二区三区性色| 亚洲欧洲精品成人久久曰| 亚洲人成77777在线观看网| 天天爽亚洲中文字幕| 亚洲日韩国产精品乱-久| 国产亚洲sss在线播放| 亚洲六月丁香婷婷综合| 丁香婷婷亚洲六月综合色| 亚洲午夜一区二区三区| 亚洲精品无码中文久久字幕| 中日韩亚洲人成无码网站| 亚洲色中文字幕在线播放| 亚洲狠狠婷婷综合久久蜜芽| 亚洲s码欧洲m码吹潮| 国产综合激情在线亚洲第一页| 国产成人久久精品亚洲小说| 亚洲日韩国产成网在线观看| 国产成人毛片亚洲精品| 中文亚洲AV片在线观看不卡 | 亚洲三级在线免费观看| 亚洲一区无码中文字幕乱码| 亚洲人成www在线播放| 亚洲另类无码专区首页| 国产精品亚洲一区二区三区在线观看 | 国内精品久久久久影院亚洲| 亚洲日韩看片无码电影| 亚洲成av人无码亚洲成av人| 国产AV日韩A∨亚洲AV电影 | 日产国产精品亚洲系列| 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲 | 亚洲综合一区二区国产精品| 亚洲视频在线观看地址| 亚洲中文字幕AV每天更新| 国产成人高清亚洲一区久久| 国产亚洲自拍一区|