由于現在大多計算機都是多核CPU,多執行緒往往會比單執行緒更快,更能夠提高并發,但提高并發并不意味著啟動更多的執行緒來執行,更多的執行緒意味著執行緒創建銷毀開銷加大、背景關系非常頻繁,你的程式反而不能支持更高的TPS,
時間片
多任務系統往往需要同時執行多道作業,作業數往往大于機器的CPU數,然而一顆CPU同時只能執行一項任務,如何讓用戶感覺這些任務正在同時進行呢? 作業系統的設計者 巧妙地利用了時間片輪轉的方式
時間片是CPU分配給各個任務(執行緒)的時間!
思考:單核CPU為何也支持多執行緒呢?
執行緒背景關系是指某一時間點 CPU 暫存器和程式計數器的內容,CPU通過時間片分配演算法來回圈執行任務(執行緒),因為時間片非常短,所以CPU通過不停地切換執行緒執行,
換言之,單CPU這么頻繁,多核CPU一定程度上可以減少背景關系切換,
超執行緒
現代CPU除了處理器核心之外還包括暫存器、L1L2快取這些存盤設備、浮點運算單元、整數運算單元等一些輔助運算設備以及內部總線等,一個多核的CPU也就是一個CPU上有多個處理器核心,就意味著程式的不同執行緒需要經常在CPU之間的外部總線上通信,同時還要處理不同CPU之間不同快取導致資料不一致的問題,
超執行緒這個概念是Intel提出的,簡單來說是在一個CPU上真正的并發兩個執行緒,由于CPU都是分時的(如果兩個執行緒A和B,A正在使用處理器核心,B正在使用快取或者其他設備,那AB兩個執行緒就可以并發執行,但是如果AB都在訪問同一個設備,那就只能等前一個執行緒執行完后一個執行緒才能執行),實作這種并發的原理是 在CPU里加了一個協調輔助核心,根據Intel提供的資料,這樣一個設備會使得設備面積增大5%,但是性能提高15%~30%,
背景關系切換
- 執行緒切換,同一行程中的兩個執行緒之間的切換
- 行程切換,兩個行程之間的切換
- 模式切換,在給定執行緒中,用戶模式和內核模式的切換
- 地址空間切換,將虛擬記憶體切換到物理記憶體
CPU切換前把當前任務的狀態保存下來,以便下次切換回這個任務時可以再次加載這個任務的狀態,然后加載下一任務的狀態并執行,任務的狀態保存及再加載, 這段程序就叫做背景關系切換,
每個執行緒都有一個程式計數器(記錄要執行的下一條指令),一組暫存器(保存當前執行緒的作業變數),堆疊(記錄執行歷史,其中每一幀保存了一個已經呼叫但未回傳的程序),
暫存器 是 CPU 內部的數量較少但是速度很快的記憶體(與之對應的是 CPU 外部相對較慢的 RAM 主記憶體),暫存器通過對常用值(通常是運算的中間值)的快速訪問來提高計算機程式運行的速度,
程式計數器是一個專用的暫存器,用于表明指令序列中 CPU 正在執行的位置,存的值為正在執行的指令的位置或者下一個將要被執行的指令的位置,
- 掛起當前任務(執行緒/行程),將這個任務在 CPU 中的狀態(背景關系)存盤于記憶體中的某處
- 恢復一個任務(執行緒/行程),在記憶體中檢索下一個任務的背景關系并將其在 CPU 的暫存器中恢復
- 跳轉到程式計數器所指向的位置(即跳轉到任務被中斷時的代碼行),以恢復該行程在程式中

執行緒背景關系切換會有什么問題呢?
背景關系切換會導致額外的開銷,常常表現為高并發執行時速度會慢串行,因此減少背景關系切換次數便可以提高多執行緒程式的運行效率,
- 直接消耗:指的是CPU暫存器需要保存和加載, 系統調度器的代碼需要執行, TLB實體需要重新加載, CPU 的pipeline需要刷掉
- 間接消耗:指的是多核的cache之間得共享資料, 間接消耗對于程式的影響要看執行緒作業區操作資料的大小
切換查看
Linux系統下可以使用vmstat命令來查看背景關系切換的次數, 其中cs列就是指背景關系切換的數目(一般情況下, 空閑系統的背景關系切換每秒大概在1500以下)

執行緒調度
搶占式調度
指的是每條執行緒執行的時間、執行緒的切換都由系統控制,系統控制指的是在系統某種運行機制下,可能每條執行緒都分同樣的執行時間片,也可能是某些執行緒執行的時間片較長,甚至某些執行緒得不到執行的時間片,在這種機制下,一個執行緒的堵塞不會導致整個行程堵塞,
java使用的執行緒調使用搶占式調度,Java中執行緒會按優先級分配CPU時間片運行,且優先級越高越優先執行,但優先級高并不代表能獨自占用執行時間片,可能是優先級高得到越多的執行時間片,反之,優先級低的分到的執行時間少但不會分配不到執行時間,

協同式調度
指某一執行緒執行完后主動通知系統切換到另一執行緒上執行,這種模式就像接力賽一樣,一個人跑完自己的路程就把接力棒交接給下一個人,下個人繼續往下跑,執行緒的執行時間由執行緒本身控制,執行緒切換可以預知,不存在多執行緒同步問題,但它有一個致命弱點:如果一個執行緒撰寫有問題,運行到一半就一直堵塞,那么可能導致整個系統崩潰,

執行緒讓出cpu的情況
- 當前運行執行緒主動放棄CPU,JVM暫時放棄CPU操作(基于時間片輪轉調度的JVM作業系統不會讓執行緒永久放棄CPU,或者說放棄本次時間片的執行權),例如呼叫
yield()方法, - 當前運行執行緒因為某些原因進入阻塞狀態,例如阻塞在I/O上
- 當前運行執行緒結束,即運行完
run()方法里面的任務
引起執行緒背景關系切換的因素
- 當前執行任務(執行緒)的時間片用完之后,系統CPU正常調度下一個任務
- 中斷處理,在中斷處理中,其他程式”打斷”了當前正在運行的程式,當CPU接收到中斷請求時,會在正在運行的程式和發起中斷請求的程式之間進行一次背景關系切換,中斷分為硬體中斷和軟體中斷,軟體中斷包括因為IO阻塞、未搶到資源或者用戶代碼等原因,執行緒被掛起,
- 用戶態切換,對于一些作業系統,當進行用戶態切換時也會進行一次背景關系切換,雖然這不是必須的,
- 多個任務搶占鎖資源,在多任務處理中,CPU會在不同程式之間來回切換,每個程式都有相應的處理時間片,CPU在兩個時間片的間隔中進行背景關系切換
因此優化手段有:
- 無鎖并發編程,多執行緒處理資料時,可以用一些辦法來避免使用鎖,如將資料的ID按照Hash取模分段,不同的執行緒處理不同段的資料
- CAS演算法,Java的Atomic包使用CAS演算法來更新資料,而不需要加鎖
- 使用最少執行緒
- 協程,單執行緒里實作多任務的調度,并在單執行緒里維持多個任務間的切換
合理設定執行緒數目既可以最大化利用CPU,又可以減少執行緒切換的開銷,
- 高并發,低耗時的情況,建議少執行緒,
- 低并發,高耗時的情況:建議多執行緒,
- 高并發高耗時,要分析任務型別、增加排隊、加大執行緒數
來源:blog.csdn.net/alex_xfboy/article/details/90722654
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
2.勁爆!Java 協程要來了,,,
3.Spring Boot 2.x 教程,太全了!
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/504652.html
標籤:Java
上一篇:NotePad++的基本使用方法
下一篇:PHP PDF轉圖片
