java 中的多線程在代碼層面是通過 new 多個 Thread 或是線程池實現(xiàn)的明刷,這只是表象婴栽,我們需要繼續(xù)審圖探究。最終的計算任務(wù)是由 CPU 完成的辈末,那么我們只要知道 CPU 如何調(diào)度 Thread 的就行了愚争,這就引出了 CPU 時間這個概念
無論是單核還是多核 CPU 都是支持多線程的,CPU 通過給每個線程分配 CPU 時間片來實這個機制挤聘,這個時間片非常短轰枝,所以 CPU 通過不停地切換線程執(zhí)行,讓我們感覺多個線程是同時執(zhí)行的组去,時間片一般是幾十毫秒(ms)
然后我們再想一想鞍陨,我們計算的數(shù)據(jù)存在內(nèi)存,但是 CPU 不在內(nèi)存中計算數(shù)據(jù)从隆,而是在 CPU 所屬的寄存器中計算任務(wù)诚撵,這就涉及到 內(nèi)存和 CPU 寄存器相互交互數(shù)據(jù)了缭裆。一個時間片段很短,很大可能一個線程的任務(wù)完不成寿烟,但是在這個 CPU 時間段結(jié)束后由別的線程搶到了隱形機會澈驼,那么 CPU 就得執(zhí)行別的線程的任務(wù),此時上一個線程未完成的任務(wù)的數(shù)據(jù)需要保存起來筛武,然后加載下一個任務(wù)的數(shù)據(jù)進來盅藻,這就是線程上下問的切換
java 的這種多線程機制由于涉及線程的上下文操作會帶來一個性能問題,線程的上下文切換和線程對象的創(chuàng)建是很消耗資源的
2個加減法循環(huán)在串行和并行時的性能對比畅铭,只有在百萬次時他們的性能在相容氏淑,百萬次以下,并行沒有性能上的優(yōu)勢硕噩,所以在 rxjava 的線程池線程設(shè)計在大型就算任務(wù)時假残,線程池線程數(shù)量 =cpu 內(nèi)核數(shù),io 等非計算耗時任務(wù)時線程池線程數(shù)量無顯示
那么如何減少上下文切換:
-
無鎖并發(fā)編程
無鎖并發(fā)編程.當任何特定的運算被阻塞的時候炉擅,所有CPU可以繼續(xù)處理其他的運算辉懒。換種方式說,在無鎖系統(tǒng)中谍失,當給定線程被其他線程阻塞的時候眶俩,所有CPU可以不停的繼續(xù)處理其他工作。無鎖算法大大增加系統(tǒng)整體的吞吐量快鱼,因為它只偶爾會增加一定的交易延遲颠印。大部分高端數(shù)據(jù)庫系統(tǒng)是基于無鎖算法而構(gòu)造的,以滿足不同級別 -
CAS 算法
Java提供了一套原子性操作的數(shù)據(jù)類型(java.util.concurrent.atomic包下)抹竹,使用CAS算法來更新數(shù)據(jù)线罕,不需要加鎖。如:AtomicInteger窃判、AtomicLong等 -
使用最少線程
避免創(chuàng)建不需要的線程钞楼,比如任務(wù)很少,但是創(chuàng)建了很多線程來處理袄琳,這樣會造成大量線程都處于等待狀態(tài) -
協(xié)程
在單線程里實現(xiàn)多任務(wù)的調(diào)度询件,并在單線程里維持多個任務(wù)間的切換,kotlin 唆樊,goland 都支持協(xié)程