摘要:并發(fā)表示在一段時間內(nèi)有多個動作存在。并發(fā)帶來的問題在享受并發(fā)編程帶來的高性能高吞吐量的同時,也會因為并發(fā)編程帶來一些意想不到弊端。并發(fā)過程中多線程之間的切換調(diào)度,上下文的保存恢復(fù)等都會帶來額外的線程切換開銷。
0x01 什么是并發(fā)
要理解并發(fā)首選我們來區(qū)分下并發(fā)和并行的概念。
并發(fā):表示在一段時間內(nèi)有多個動作存在。
并行:表示在同一時間點有多個動作同時存在。
例如:
此刻我正在寫博客,但是我寫著寫著停下來吃一下東西(菠蘿片)再寫、再吃。這兩個動作在一段時間內(nèi)都在發(fā)生著,這可以理解為并發(fā)。
另一方面我在寫這個博客的同時我在聽音樂。那么同時存在的兩個動作(寫博客、聽音樂)是同時在發(fā)生的這就是所謂的并行。
從上面兩個概念明顯可以感受到并發(fā)是包含并行操作。所以我們通常說的并發(fā)編程對于cpu來說有可能是并發(fā)的在執(zhí)行也有可能是交替的在執(zhí)行。
說到這里你可能會問為什么我們需要并發(fā)編程?
在求解單個問題的時候凡是涉及多個執(zhí)行流程的編程模式都叫并發(fā)編程。
硬件的發(fā)展推動軟件的進度,多核時代的到來
應(yīng)用系統(tǒng)對性能和吞吐量的苛刻要求
大數(shù)據(jù)時代的到來
移動互聯(lián)網(wǎng)、云計算對計算體系的沖擊
0x03 并發(fā)編程方式Java:多進程/多線程的并發(fā)實現(xiàn)方式
Go:協(xié)程--用戶態(tài)實現(xiàn)的多線程方式(goroutine)
Java并發(fā)模型在介紹java并發(fā)模型前我們來介紹下系統(tǒng)對多線程的實現(xiàn)方式。系統(tǒng)支持用戶態(tài)線程和內(nèi)核態(tài)兩種線程的實現(xiàn)方式,內(nèi)核態(tài)線程是cpu去調(diào)度的最小單位,所以這牽涉到用戶態(tài)線程和內(nèi)核態(tài)線程之間的映射關(guān)系,用戶態(tài)線程:內(nèi)核態(tài)線程 = 1:1 、 N:1 、 M:N。
1:1 這種映射關(guān)系充分利用多核的優(yōu)勢,但是這種方式在用戶態(tài)進行線程切換的過程中都會涉及到內(nèi)核態(tài)線程之間的切換,切換開銷大。(主要涉及內(nèi)核線程運行時上下文的保存與恢復(fù))
N:1 沒法充分利用多核的優(yōu)勢,但是這種由于是用戶態(tài)的內(nèi)存切換不涉及內(nèi)核態(tài)線程之間的切換所以這種映射關(guān)系在線程之間切換代價小。
M:N 這種是上面兩種映射關(guān)系的結(jié)合體,集合了上面兩種映射關(guān)系的優(yōu)勢,但是這也增加了線程之間這種映射關(guān)系的調(diào)度復(fù)雜度。
Java的并發(fā)編程模式是通過1:1這種映射關(guān)系來實現(xiàn)線程之間的并發(fā)調(diào)度。
Go并發(fā)模型Go的并發(fā)模式是通過M:N這種方式來實現(xiàn)并發(fā)調(diào)度的。
Go調(diào)度器中有三種重要結(jié)構(gòu):M(posix thread)、P(調(diào)度上下文,一般數(shù)量設(shè)置為和機器內(nèi)核數(shù)相同,這樣能充分發(fā)揮機器的并發(fā)性能)、G(goroutine)。
一個調(diào)度上下文可以包含多個Goroutine,多個上下文所以可以所有的Goroutine都能并發(fā)的運行在CPU的多核上面。
如果有Goroutine發(fā)現(xiàn)找不到調(diào)度上下文,就會被放到global runqueue中,等清閑的調(diào)度上下文來撈取它進行調(diào)度。
如果調(diào)度上下文上面掛載的所有Goroutine都已經(jīng)執(zhí)行完畢,此時他會去global runqueue中獲取Goroutine,如果發(fā)現(xiàn)此時沒有獲取到,則會去別的調(diào)度上文中搶Goroutine,一般一次搶都是搶此時被搶調(diào)度上下文的一半Goroutine,確保充分利用M去被多核調(diào)度。
在享受并發(fā)編程帶來的高性能、高吞吐量的同時,也會因為并發(fā)編程帶來一些意想不到弊端。
資源的消耗,要管理這么多用戶線程、內(nèi)核線程、用戶線程內(nèi)核線程之間的切換調(diào)度,上下文等等這些都是由于引用了并發(fā)編程所帶來的額外消耗。
并發(fā)過程中多線程之間的切換調(diào)度,上下文的保存恢復(fù)等都會帶來額外的線程切換開銷。
編碼、測試的復(fù)雜性。和我們生活中的例子很相像,三五個人一起出去活動很容易把控,如果帶著幾十、上百人的團隊出去活動這些都會帶來額外的管理上的開銷。
真的是有陽關(guān)的地方就有黑暗??!
上面這些都是我們沒法避免的一些問題,要引用并發(fā)編程必然會要付出點額外的代價才行。但是并發(fā)編程還帶來了一個不能忽視的問題,線程之間對同一資源的競爭訪問,造成內(nèi)存對象狀態(tài)和自己的想象千差萬別。
java線程對內(nèi)存的理解分為兩部分:線程工作內(nèi)存(每個線程獨有的)、共享內(nèi)存也叫主內(nèi)存(所有的線程所共有的),下面是java線程對內(nèi)存中Count對象的一次修改操作。
從主線程中讀取Count對象放入線程工作內(nèi)存,后面的讀取修改都在線程工作內(nèi)存中,最后(更新到主內(nèi)存的時間不是確定的,可能會插入別的操作在store、write之間)更新到主內(nèi)存中。所有的上述操作都是順序執(zhí)行的,但是不保證連續(xù)執(zhí)行。
volatile變量、synchronized塊執(zhí)行結(jié)束后能保證每次去更新的值都會立即寫入到主內(nèi)存中。
volatile變量很多人會認為這樣就是線程安全的,但是通過上面我們可以看到如果兩個線程同時去讀了一個volatile變量,最后一前一后更新到主內(nèi)存中,這樣也會出現(xiàn)寫丟失的情況,所以volatile不能保證線程安全。
1) 定義線程池
private static final ExecutorService executor = Executors.newFixedThreadPool(20);
2)定義并發(fā)服務(wù)
CompletionServicecompletionService = new ExecutorCompletionService (executor);
3)提交并發(fā)任務(wù)
completionService.submit(new Callable() { @Override public void call() throws Exception { return ; } });
4)等待并發(fā)結(jié)果
for (int i = 0; i < taskSize; ++i) { Futurefuture = completionService.poll(TIME_OUT, TimeUnit.SECONDS); Result result = future.get(); }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/70030.html
摘要:所有示例代碼請見下載于基本概念并發(fā)同時擁有兩個或者多個線程,如果程序在單核處理器上運行多個線程將交替地換入或者換出內(nèi)存這些線程是同時存在的,每個線程都處于執(zhí)行過程中的某個狀態(tài),如果運行在多核處理器上此時,程序中的每個線程都 所有示例代碼,請見/下載于 https://github.com/Wasabi1234... showImg(https://upload-images.jians...
摘要:比如需要用多線程或分布式集群統(tǒng)計一堆用戶的相關(guān)統(tǒng)計值,由于用戶的統(tǒng)計值是共享數(shù)據(jù),因此需要保證線程安全。如果類是無狀態(tài)的,那它永遠是線程安全的。參考探索并發(fā)編程二寫線程安全的代碼 線程安全類 保證類線程安全的措施: 不共享線程間的變量; 設(shè)置屬性變量為不可變變量; 每個共享的可變變量都使用一個確定的鎖保護; 保證線程安全的思路: 1. 通過架構(gòu)設(shè)計 通過上層的架構(gòu)設(shè)計和業(yè)務(wù)分析來避...
摘要:精讀前端可以從多個角度理解,比如規(guī)范框架語言社區(qū)場景以及整條研發(fā)鏈路。同是前端未來展望,不同的文章側(cè)重的格局不同,兩個標題相同的文章內(nèi)容可能大相徑庭。作為使用者,現(xiàn)在和未來的主流可能都是微軟系,畢竟微軟在操作系統(tǒng)方面人才儲備和經(jīng)驗積累很多。 1. 引言 前端展望的文章越來越不好寫了,隨著前端發(fā)展的深入,需要擁有非常寬廣的視野與格局才能看清前端的未來。 筆者根據(jù)自身經(jīng)驗,結(jié)合下面幾篇文章...
摘要:函數(shù)式編程與面向?qū)ο缶幊叹幊痰谋举|(zhì)之劍目錄編程的本質(zhì)讀到兩篇文章寫的不錯綜合摘錄一下復(fù)合是編程的本質(zhì)函數(shù)式程序員在洞察問題方面會遵循一個奇特的路線。在面向?qū)ο缶幊讨?,類或接口的聲明就是表面? 函數(shù)式編程與面向?qū)ο缶幊蘙5]:編程的本質(zhì) 之劍 2016.5.6 01:26:31 編程的本質(zhì) 讀到兩篇文章,寫的不錯, 綜合摘錄一下 復(fù)合是編程的本質(zhì) 函數(shù)式程序員在洞察問題方面會遵循...
閱讀 2363·2021-11-16 11:52
閱讀 2338·2021-11-11 16:55
閱讀 765·2021-09-02 15:41
閱讀 2996·2019-08-30 15:54
閱讀 3156·2019-08-30 15:54
閱讀 2265·2019-08-29 15:39
閱讀 1520·2019-08-29 15:18
閱讀 981·2019-08-29 13:00