JAVA多執行緒16 執行緒上下文切換

2021-09-24 09:02:34 字數 2373 閱讀 1288

併發程式設計的目的是為了讓程式執行得更快,但是並不是啟動更多的執行緒就能讓程式最大限度地併發執行。在進行併發程式設計時,如果希望通過多執行緒執行任務讓程式執行得更快,會面臨非常多的挑戰,比如上下文切換的問題、死鎖的問題,以及受限於硬體和軟體的資源限制問題,本文要研究的是上下文切換的問題。

什麼是上下文切換

即使是單核cpu也支援多執行緒執行**,cpu通過給每個執行緒分配cpu時間片來實現這個機制。時間片是cpu分配給各個執行緒的時間,因為時間片非常短,所以cpu通過不停地切換執行緒執行,讓我們感覺多個執行緒時同時執行的,時間片一般是幾十毫秒(ms)。

cpu通過時間片分配演算法來迴圈執行任務,當前任務執行乙個時間片後會切換到下乙個任務。但是,在切換前會儲存上乙個任務的狀態,以便下次切換回這個任務時,可以再次載入這個任務的狀態,從任務儲存到再載入的過程就是一次上下文切換

這就像我們同時讀兩本書,當我們在讀一本英文的技術書籍時,發現某個單詞不認識,於是便開啟中英文詞典,但是在放下英文書籍之前,大腦必須先記住這本書讀到了多少頁的第多少行,等查完單詞之後,能夠繼續讀這本書。這樣的切換是會影響讀書效率的,同樣上下文切換也會影響多執行緒的執行速度。

上下文切換**測試

public class contextswitchtest

private static void concurrency() throws exception

}});

thread.start();

int b = 0;

for (long i = 0; i < count; i++)

thread.join();

long time = system.currenttimemillis() - start;

system.out.println("concurrency:" + time + "ms, b = " + b);

}private static void serial()

int b = 0;

for (int i = 0; i < count; i++)

long time = system.currenttimemillis() - start;

system.out.println("serial:" + time + "ms, b = " + b + ", a = " + a);}}

修改上面的count值,即修改迴圈次數,看一下序列執行和併發執行的時間測試結果:

迴圈次數序列執行耗時/ms併發執行耗時/ms序列和併發對比

1億78

50併發快約0.5倍

1000萬106

併發快約0.5~1倍

100萬32

差不多10萬22

差不多1萬01

差不多,十幾次執行下來,總體而言序列略快

從表中可以看出,100次併發執行累加以下,序列執行和併發執行的執行速度總體而言差不多,1萬次以下序列執行甚至還可以說是略快。為什麼併發執行的速度會比序列慢呢?這就是因為執行緒有建立和上下文切換的開銷

引起執行緒上下文切換的原因

對於我們經常使用的搶占式作業系統而言,引起執行緒上下文切換的原因大概有以下幾種:

當前執行任務的時間片用完之後,系統cpu正常排程下乙個任務

當前執行任務碰到io阻塞,排程器將此任務掛起,繼續下一任務

多個任務搶占鎖資源,當前任務沒有搶到鎖資源,被排程器掛起,繼續下一任務

使用者**掛起當前任務,讓出cpu時間

硬體中斷

上下文切換次數檢視

在linux系統下可以使用vmstat命令來檢視上下文切換的次數,下面是利用vmstat檢視上下文切換次數的示例:

cs(context switch)表示上下文切換的次數,從圖中可以看到,上下文每秒鐘切換500~600次左右。

如果要檢視上下文切換的時長,可以利用lmbench3,這是乙個效能分析工具。

如何減少上下文切換

既然上下文切換會導致額外的開銷,因此減少上下文切換次數便可以提高多執行緒程式的執行效率。減少上下文切換的方法有無鎖併發程式設計、cas演算法、使用最少執行緒和使用協程。

【毒雞湯:我相信賈伯斯說的,只有那些瘋狂到認為自己可以改變世界的人才能真正地改變世界。面對壓力,我可以挑燈夜戰、不眠不休;面對困難,我願意迎難而上、永不退縮。

java多執行緒 上下文切換

併發程式設計的目的是為了讓程式執行得更快,但是並不是啟動更多的執行緒就能讓程式最大限度地併發執行。在進行併發程式設計時,如果希望通過多執行緒執行任務讓程式執行得更快,會面臨非常多的挑戰,比如上下文切換的問題 死鎖的問題,以及受限於硬體和軟體的資源限制問題,本文要研究的是上下文切換的問題。即使是單核c...

Java執行緒上下文 ThreadLocal的那些事

threadlocal 通常被稱作執行緒本地變數或者執行緒本地儲存。其含義是threadlocal為變數在每個執行緒中都建立乙個副本,則每個執行緒可以訪問自身內部的副本變數。概念總是抽象而且晦澀的,我們從兩個例子說起。如下圖,有個多層呼叫的情況,如果我們需要傳遞某個中間結果在這幾層呼叫關係之間,應該...

多執行緒上下文切換

前言 併發程式設計的目的是為了讓程式執行得更快,但是並不是啟動更多的執行緒就能讓程式最大限度地併發執行。在進行併發程式設計時,如果希望通過多執行緒執行任務讓程式執行得更快,會面臨非常多的挑戰,比如上下文切換的問題 死鎖的問題,以及受限於硬體和軟體的資源限制問題,本文要研究的是上下文切換的問題。什麼是...