2019-11-03


前言:

  這個是我一個粉絲問我的問題河胎,一個剛從python轉(zhuǎn)Java的粉絲朋友镊屎。特此拿出來分享一下妥色。希望能對大家在這塊有迷惑的有所幫助吨些。以下是他的問題

面試時多線程是Java繞不去的坎垄惧,就有幾個問題

  1.為什么多線程在Java中這么重要刁愿?

  2.據(jù)說多線程會出現(xiàn)難以排查的BUG,那么使用協(xié)程的話能否避免這些BUG呢到逊?

  3.go的協(xié)程是可以跑滿整個核心的铣口,但Java是不是除非從語言底層改造,否則做不到這一點觉壶?

  4.Kotlin支持協(xié)程脑题,是否用起來比多線程好呢?

  5.所以铜靶,學(xué)好Java中的多線程是否還有必要呢叔遂?

答:

1.為什么多線程在Java中這么重要

  多線程在哪里都很重要

2.據(jù)說多線程會出現(xiàn)難以排查的BUG,那么使用協(xié)程的話能否避免這些BUG呢

  不能旷坦,其實協(xié)程需要學(xué)習(xí)的東西都更多掏熬。如果你學(xué)過C#的話,你去好好分析一個await函數(shù)里面的任意兩行代碼是不是執(zhí)行在同一個線程里的秒梅,以及為什么旗芬,初學(xué)者都得頭痛一陣子。然而你這個不知道的話捆蜀,出了bug你連改都不會改疮丛。

  用了協(xié)程你也不可避免會遇到數(shù)據(jù)共享的問題幔嫂,要共享你要么atom要么interlocked要么上鎖,這完全是多線程的內(nèi)容誊薄。這個時候你甚至得去弄明白協(xié)程跟線程在實現(xiàn)的時候是如何對應(yīng)的履恩,不然就抓瞎。

3.go的協(xié)程是可以跑滿整個核心的呢蔫,但Java是不是除非從語言底層改造切心,否則做不到這一點

  Java吧這個任務(wù)交給你了,你行程序就行片吊,你不行程序就不行绽昏。

4.Kotlin支持協(xié)程,是否用起來比多線程好呢

  參見2

? ? 所以俏脊,學(xué)好Java中的多線程是否還有必要呢

 學(xué)什么語言都有必要學(xué)多線程全谤,除了不讓你開線程的。(不是黑)

結(jié)論與思考

  先說結(jié)論:協(xié)程是非常值得學(xué)習(xí)的概念爷贫,它是多任務(wù)編程的未來认然。但是Java全力推進這個事情的動力并不大。

  先返回到問題的本源漫萄。當(dāng)我們希望引入?yún)f(xié)程卷员,我們想解決什么問題。我想不外乎下面幾點:

  節(jié)省資源卷胯,輕量子刮,具體就是:

  節(jié)省內(nèi)存,每個線程需要分配一段棧內(nèi)存窑睁,以及內(nèi)核里的一些資源

  節(jié)省分配線程的開銷(創(chuàng)建和銷毀線程要各做一次syscall)

  節(jié)省大量線程切換帶來的開銷

  與NIO配合實現(xiàn)非阻塞的編程挺峡,提高系統(tǒng)的吞吐

  使用起來更加舒服順暢(async+await,跑起來是異步的担钮,但寫起來感覺上是同步的)

我們分開來講下橱赠。

1. 先說內(nèi)存。拿Java Web編程舉例子箫津,一個tomcat上的woker線程池的最大線程數(shù)一般會配置為50~500之間(目前springboot的默認值給的200)狭姨。也就是說同一時刻可以接受的請求最多也就是這么多。如果超過了最大值苏遥,請求直接打失敗拒絕處理饼拍。假如每個線程給128KB,500個線程放一起的內(nèi)存占用量大概是60+MB田炭。如果真的有瓶頸师抄,也許CPU,IO教硫,帶寬叨吮,DB的CPU等會有瓶頸辆布,但這點內(nèi)存量的增幅對于動輒數(shù)個GB的Java運行時進程來說似乎并不是什么大問題。

2. 換一個場景茶鉴,比如IM服務(wù)器锋玲,需要同時處理大量空閑的鏈接(可能要幾十萬,上百萬)涵叮。這時候用connection per thread就很不劃算了惭蹂。但是可以直接改用netty去處理這類問題。你可以理解為NIO + woker thread大致就是一套“協(xié)程”围肥,只不過沒有實現(xiàn)在語法層面剿干,寫起來不優(yōu)雅而已。問題是穆刻,你的場景真的處理了并發(fā)幾十萬,上百萬的連接嗎杠步?

3. 再說創(chuàng)建/銷毀線程的開銷氢伟。這個問題在Java里通過線程池得到了很好的解決。你會發(fā)現(xiàn)即便你用vert.x或者kotlin的協(xié)程幽歼,歸根到底也是要靠線程池工作的朵锣。goroutine相當(dāng)于設(shè)置一個全局的“線程池”,GOMAXPROCS就是線程池的最大數(shù)量甸私;而Java可以自由設(shè)置多個不同的線程池(比如處理請求一套诚些,異步任務(wù)另外一套等)。kotlin利用這個機制來構(gòu)建多個不同的協(xié)程scope皇型。這看起來似乎會更靈活一點诬烹。

4. 然后是線程的切換開銷。線程的切換實際上只會發(fā)生在那些“活躍”的線程上弃鸦。對于類似于Web的場景绞吁,大量的線程實際上因為IO(發(fā)請求/讀DB)而掛起,根本不會參與OS的線程切換』8瘢現(xiàn)實當(dāng)中一個最大200線程的服務(wù)器可能同一時刻的“活躍線程”總數(shù)只有數(shù)十而已家破。其開銷沒有想象的那么大。為了避免過大的線程切換開銷购岗,真正要防范的是同時有大量“活躍線程”汰聋。這個事情我自己上學(xué)的時候干過,當(dāng)時是寫了一個網(wǎng)絡(luò)模擬器喊积。每一個節(jié)點烹困,每一個鏈路都由一個線程實現(xiàn)。模擬跑起來后注服,同時的活躍線程上千韭邓。當(dāng)時整個機器瞬間卡死措近,直到kill掉這個程序。

5. 此外說說與NIO的配合女淑。在Java這個生態(tài)里Java NIO/Netty/Vert.X/rxJava/Akka可以任意選擇瞭郑。一般來講,Netty可以解決絕大部分因為IO的等待造成資源浪費的問題鸭你。Vert.X/rxJava屈张。可以讓程序?qū)懙母印皟?yōu)雅”一點(見仁見智)袱巨。Akka就是Java世界里對“原教旨OO“的實現(xiàn)阁谆,很有特色。的確愉老,用NIO + completedFuture/handler/lambda不如async+await寫起來舒服场绿,但起碼是可以干活的。

6. 如果真的要較真Java的NIO用于業(yè)務(wù)的問題嫉入,其核心痛點應(yīng)該是JDBC焰盗。這是個誕生了幾十年的,必須使用Blocking IO的DB交互協(xié)議咒林。其上承載了Java龐大的生態(tài)和業(yè)務(wù)邏輯熬拒。Java要改自己的編程方式,必須得重新設(shè)計和實現(xiàn)JDBC垫竞,就像https://github.com/vert-x3/vertx-mysql-postgresql-client 那樣做澎粟。問題是,社區(qū)里這種“異步JDBC”還沒有支持oracle欢瞪、sql server等傳統(tǒng)DB活烙。對mysql和postgres的支持還需要繼續(xù)趟坑~

7. 如果認真閱讀上面這些需要“協(xié)程”解決的問題,就會發(fā)現(xiàn)基本上都可以以各種方式解決引有。覺得線程耗資源瓣颅,可以控制線程總數(shù),可以減少線程stack的大小譬正,可以用線程池配置max和min idle等等宫补。想要go的channel,可以上disruptor曾我》叟拢可以說,Java這個生態(tài)里盡管沒有“協(xié)程”這個第一級別的概念抒巢,但是要解決問題的工具并不缺贫贝。

8. Java僅僅是沒有解決”協(xié)程“在Java中的定義,以及“寫得優(yōu)雅“這個問題。從工程角度稚晚,“寫得優(yōu)雅”的優(yōu)勢并沒有很多追新的人想象的那么關(guān)鍵崇堵。C#也并非因為有了async await就搶了Java的市場分毫。而反過來客燕,如果java社區(qū)全力推進這個事情鸳劳,Java歷史上的生態(tài)的積累卻因為協(xié)程的出現(xiàn)而進行大換血。想像一下如果沒有thread也搓,也沒有ThreadLocal赏廓,@Transactional不起作用了,又沒有等價的工具傍妒,是不是很郁悶幔摸?這么看來怎么著都不是個劃算的事情。我想Oracle對此并不會有太大興趣颤练。OpenJDK的loom能不能成既忆,如果真的release多少Java程序員愿意使用,師母已呆嗦玖。據(jù)我所知在9012年的今天尿贫,還有大量的Java6程序員。

9. 其他新的語言歷史包袱少踏揣,比較容易重新思考“什么是現(xiàn)代的multi-task編程的方式“這個大主題。kotlin的協(xié)程匾乓、go的goroutine捞稿、javascript的async await、python的asyncio拼缝、swift的GCD都給了各自的答案娱局。如果真的想入坑Java這個體系的“協(xié)程”,就從kotlin開始吧咧七,畢竟可以混合編程衰齐。

最后說一句,多線程容易出bug主要因為:

  “搶占“式的線程切換 —— 你無法確定兩個線程訪問數(shù)據(jù)的順序继阻,一切都很隨機

  “同步“不可組裝 —— 同步的代碼組裝起來也不同步耻涛,必須加個更大的同步塊

  協(xié)程能不能避免容易出bug的缺陷,主要看能不能避免上面兩個問題瘟檩。如果協(xié)程底層用的還是線程池抹缕,兩個協(xié)程還是通過共享內(nèi)存通訊,那么多線程該出什么bug墨辛,多協(xié)程照樣出卓研。javascript里不出這種bug是因為其用戶線程就一個,不會出現(xiàn)線程切換,也不用同步奏赘;go是建議用channel做goroutine的通訊寥闪。如果go routine不用channel,而是用共享變量磨淌,并且沒有用Sync包控制一下疲憋,還是會出bug。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伦糯,一起剝皮案震驚了整個濱河市柜某,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌敛纲,老刑警劉巖喂击,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異淤翔,居然都是意外死亡翰绊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門旁壮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來监嗜,“玉大人,你說我怎么就攤上這事抡谐〔闷妫” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵麦撵,是天一觀的道長刽肠。 經(jīng)常有香客問我,道長免胃,這世上最難降的妖魔是什么音五? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮羔沙,結(jié)果婚禮上躺涝,老公的妹妹穿的比我還像新娘。我一直安慰自己扼雏,他們只是感情好坚嗜,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呢蛤,像睡著了一般惶傻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上其障,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天银室,我揣著相機與錄音,去河邊找鬼。 笑死蜈敢,一個胖子當(dāng)著我的面吹牛辜荠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抓狭,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼伯病,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了否过?” 一聲冷哼從身側(cè)響起午笛,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苗桂,沒想到半個月后药磺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡煤伟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年癌佩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片便锨。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡围辙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出放案,到底是詐尸還是另有隱情姚建,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布吱殉,位于F島的核電站桥胞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏考婴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一催烘、第九天 我趴在偏房一處隱蔽的房頂上張望沥阱。 院中可真熱鬧,春花似錦伊群、人聲如沸考杉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崇棠。三九已至,卻和暖如春丸卷,著一層夾襖步出監(jiān)牢的瞬間枕稀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萎坷,地道東北人凹联。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像哆档,于是被迫代替她去往敵國和親蔽挠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 姓名:劉偉勛 —寧波市鎮(zhèn)海承迪文具有限公司 【日精進打卡第515天】 【知~學(xué)習(xí)】 《...
    君臨天下_7055閱讀 394評論 0 0
  • 也談?wù)Z文學(xué)習(xí) 沙區(qū)教研室 卿紅燕 聽過這樣一個故事:很久以前瓜浸,...
    41626a49b1c2閱讀 148評論 0 1
  • 也談?wù)Z文學(xué)習(xí) 卿紅燕 聽過這樣一個故事:很久以前澳淑,一位病危的老酋長...
    41626a49b1c2閱讀 452評論 0 0
  • 生活中有很多的不經(jīng)意。不經(jīng)意間愛了插佛,不經(jīng)意間犯錯了杠巡,不經(jīng)意間收獲了,不經(jīng)意間被罰了...... 因著急...
    N落花成蔭閱讀 126評論 0 1
  • “姐姐朗涩,你若想他忽孽,便去見他吧。你便是要將熙國給他谢床,我也不在意兄一,反正這熙國的天下都是你打下來的∈锻龋” 今晚的夜色很深出革,...
    狐則閱讀 618評論 0 0