本書由科大訊飛高級系統(tǒng)架構(gòu)師撰寫,結(jié)合大量源碼與圖示,通俗易懂;自頂向下解析JDK、JVM、Linux中的Java線程通信機(jī)制、同步機(jī)制、鎖機(jī)制、原子計(jì)數(shù)器、線程安全容器、線程池的實(shí)現(xiàn)原理與應(yīng)用技巧。全書共12章,分為三篇。
基礎(chǔ)篇(第1~5章),從Linux的線程基礎(chǔ)講起,重點(diǎn)從JDK、JVM、Linux多個維度講解Java線程的設(shè)計(jì)、通信與同步機(jī)制,如內(nèi)存一致性、內(nèi)存屏障、多線程間數(shù)據(jù)通信、并發(fā)控制等核心知識,從而在實(shí)際開發(fā)中提高程序的性能和穩(wěn)定性。
進(jìn)階篇(第6~9章),從CPU的架構(gòu)講起,重點(diǎn)講解鎖算法(MCS、CLH、AQS)、Java鎖機(jī)制、原子計(jì)數(shù)器、線程并發(fā)容器、線程池的設(shè)計(jì)原理與實(shí)現(xiàn),以期讓讀者掌握J(rèn)ava線程的進(jìn)階知識,不僅能開發(fā)出高性能的程序,而且遇到問題可以舉一反三,找到最佳方案。
應(yīng)用篇(第10~11章),詳細(xì)講解Java線程的常見模型與使用技巧。以電商真實(shí)場景為例,從面臨的挑戰(zhàn)、基于Java多線程的實(shí)現(xiàn)方案與優(yōu)化等角度層層遞進(jìn),讓讀者感受真實(shí)的Java線程“威力”。 最后,總結(jié)多線程編程的常見問題與使用技巧。
本書由科大訊飛高級系統(tǒng)架構(gòu)師撰寫,結(jié)合大量源碼與圖示,通俗易懂;自頂向下解析JDK、JVM、Linux中的Java線程通信機(jī)制、同步機(jī)制、鎖機(jī)制、原子計(jì)數(shù)器、線程安全容器、線程池的實(shí)現(xiàn)原理與應(yīng)用技巧。
Preface 前 言
為什么要寫這本書
2002年的秋天,一個偶然的機(jī)會我接觸到了計(jì)算機(jī)編程。我編寫的第一個程序成功運(yùn)行所帶來的新奇與成就感,讓我對計(jì)算機(jī)充滿了熱愛。在高考填報(bào)志愿時(shí),我毫不猶豫地選擇了計(jì)算機(jī),憧憬著未來成為一名出色的工程師。
2021年我36歲生日那天,在與家人聊天的時(shí)候,我發(fā)現(xiàn)自己在不知不覺中已經(jīng)與Java“共事”近10年了。在十多年的技術(shù)求索之路上,王國維先生的三重人生境界不斷激勵著我前行:
古今之成大事業(yè)、大學(xué)問者,必經(jīng)過三種之境界:“昨夜西風(fēng)凋碧樹,獨(dú)上高樓,望盡天涯路!贝说谝痪骋。“衣帶漸寬終不悔,為伊消得人憔悴!贝说诙骋。“眾里尋他千百度,驀然回首,那人卻在,燈火闌珊處!贝说谌骋病
一個技術(shù)人員要想成為一名真正的工匠,就必須耐得住寂寞,經(jīng)得起時(shí)間的考驗(yàn),并且始終保持內(nèi)心深處的熱愛。
回顧過去十多年的技術(shù)之路,我得到了很多師長的提攜與指點(diǎn),受到100多本技術(shù)書籍的“滋養(yǎng)”。正所謂“前人栽樹,后人乘涼”,我也想為Java社區(qū)略盡微薄之力。
十多年來,我一直深耕互聯(lián)網(wǎng)領(lǐng)域的系統(tǒng)研發(fā),在Java多線程編程方面積累了一定的經(jīng)驗(yàn)。在工作之余,我也會和技術(shù)社區(qū)中的朋友交流Java多線程技術(shù),發(fā)現(xiàn)很多朋友在技術(shù)細(xì)節(jié)上存在諸多困惑。而目前大部分書籍和資料多以功能介紹為主,很少有剖析Java線程的設(shè)計(jì)原理的。所以,我決定寫一本書,旨在從Linux、JVM、Java多個方面來詳細(xì)闡述Java線程的技術(shù)原理與實(shí)現(xiàn)細(xì)節(jié)。
本書將為讀者提供一個全新的視角,秉承“大道至簡”的主導(dǎo)思想,只介紹Java多線程開發(fā)中最值得關(guān)注的內(nèi)容,致力于底層實(shí)現(xiàn)原理的分析,而非API的使用。
本書特色
隨著互聯(lián)網(wǎng)的發(fā)展,會有越來越多的公司進(jìn)行數(shù)字化轉(zhuǎn)型。在數(shù)字化轉(zhuǎn)型的過程中,高并發(fā)、高性能是衡量系統(tǒng)性能的核心指標(biāo),越來越多的公司對從業(yè)人員的多線程編程能力提出了更高的要求。本書將打通Java、JVM、Linux的全鏈路技術(shù)棧,剖析Java多線程的實(shí)現(xiàn)原理,以便讀者厘清現(xiàn)象與本質(zhì)。同時(shí),本書結(jié)合實(shí)際業(yè)務(wù)場景沉淀出多線程編程模型,以便讀者快速獲得多線程編程能力。
本書中的一些實(shí)操例子,開發(fā)工程師可直接應(yīng)用于實(shí)際業(yè)務(wù)場景中;設(shè)計(jì)原理和深入分析的內(nèi)容,可幫助架構(gòu)師拓展解決問題的思路;工具和問題分析的內(nèi)容,可幫助技術(shù)人員診斷線上環(huán)境中的系統(tǒng)問題。
讀者對象
Java開發(fā)工程師
系統(tǒng)架構(gòu)師
運(yùn)維工程師
并發(fā)編程愛好者以及其他對Java技術(shù)感興趣的人員
如何閱讀本書
本書從Java多線程基礎(chǔ)知識、進(jìn)階功能、實(shí)際應(yīng)用三個維度展開討論,分為三篇,共11章內(nèi)容。
基礎(chǔ)篇(第1~5章),著重講解Java線程的基礎(chǔ)知識、設(shè)計(jì)原理與具體實(shí)現(xiàn)。
第1章 從Linux線程基礎(chǔ)出發(fā),詳細(xì)講解Linux系統(tǒng)的進(jìn)程、線程、任務(wù)調(diào)度等概念,并詳細(xì)闡述Linux線程庫Pthread的使用。
第2章 詳細(xì)講解JVM的邏輯架構(gòu),涵蓋JVM的線程模型、JNI訪問等組成部件。
第3章 詳細(xì)講解Java線程的基本概念、多線程帶來的問題、Java內(nèi)存模型,以及JVM內(nèi)存屏障的實(shí)現(xiàn)、JVM線程的底層實(shí)現(xiàn)與生命周期等。
第4章 詳細(xì)講解Java線程的睡眠、等待、中斷等線程通信機(jī)制的設(shè)計(jì)原理與JVM實(shí)現(xiàn)。
第5章 詳細(xì)講解Java的synchronized、volatile、CAS等同步控制機(jī)制的設(shè)計(jì)原理與JVM實(shí)現(xiàn)。
進(jìn)階篇(第6~9章),著重講解Java多線程的高階功能的實(shí)現(xiàn)原理。
第6章 詳細(xì)講解鎖的演進(jìn)過程、Java的AQS設(shè)計(jì)原理以及常見鎖機(jī)制的具體實(shí)現(xiàn)。
第7章 詳細(xì)講解Java的各種原子操作類的設(shè)計(jì)原理與具體實(shí)現(xiàn)。
第8章 詳細(xì)講解Java的List、Map、Queue等線程安全的并發(fā)容器的設(shè)計(jì)原理與具體實(shí)現(xiàn)。
第9章 詳細(xì)講解Java中常見的線程池的設(shè)計(jì)原理與具體實(shí)現(xiàn)。
應(yīng)用篇(第10、11章),著重講解Java多線程的常見模型與編程技巧。
第10章 總結(jié)Java線程池的幾種常見使用模型,以及在業(yè)務(wù)場景中的實(shí)現(xiàn)案例。
第11章 總結(jié)多線程編程中的常見問題,并給出應(yīng)對這些問題的編程技巧。
其中,第3~8章為本書的重點(diǎn)章,如果你沒有充足的時(shí)間完成全書的閱讀,可以選擇閱讀這些重點(diǎn)章。如果你是一名初學(xué)者,請?jiān)陂_始本書閱讀之前,先學(xué)習(xí)一些Java多線程的基礎(chǔ)理論知識。
勘誤和支持
由于寫作水平有限,編寫時(shí)間倉促,書中難免會出現(xiàn)一些錯誤或者不準(zhǔn)確的地方,懇請讀者批評指正。如果你有更多的寶貴意見,可以通過微信sky_ccy與我溝通。同時(shí),你也可以通過郵箱easyjavathread@gmail.com與我聯(lián)系。期待得到你的真摯反饋,讓我們在技術(shù)之路上互勉共進(jìn)。
致謝
感謝知名操作系統(tǒng)專家彭東,他幫忙審校了第1章,并對該章內(nèi)容提出了一些非常中肯的建議。
特別感謝我的太太林燕女士、女兒可歆和兒子喬治,我為寫作這本書犧牲了很多陪伴他們的時(shí)間,但也正因?yàn)橛辛怂麄兊母冻雠c支持,我才能堅(jiān)持寫下去。
同時(shí),感謝在我成長路上幫助過我的領(lǐng)導(dǎo)、師長、朋友,是他們的指導(dǎo)讓我成了更好的自己。
謹(jǐn)以此書獻(xiàn)給我最親愛的家人,以及眾多熱愛Java技術(shù)的朋友們!
儲誠益
儲誠益
科大訊飛高級系統(tǒng)架構(gòu)師,致力于研究下一代工業(yè)互聯(lián)網(wǎng)系統(tǒng)架構(gòu)、人工智能、中小制造企業(yè)數(shù)字化轉(zhuǎn)型。擁有十余年的IT領(lǐng)域工作經(jīng)驗(yàn),曾就職于多家知名IT企業(yè)并負(fù)責(zé)技術(shù)架構(gòu)設(shè)計(jì)和管理工作,積累了豐富的分布式架構(gòu)、大數(shù)據(jù)、云計(jì)算以及大規(guī)模IT系統(tǒng)等的建設(shè)、實(shí)施、咨詢、管理經(jīng)驗(yàn)。
目 錄 Contents
前言
基礎(chǔ)篇
第1章 Linux線程基礎(chǔ)2
1.1 Linux進(jìn)程2
1.1.1 深入理解進(jìn)程2
1.1.2 進(jìn)程描述符3
1.1.3 進(jìn)程創(chuàng)建6
1.1.4 上下文切換7
1.2 Linux進(jìn)程間通信7
1.2.1 信號 8
1.2.2 管道9
1.2.3 共享內(nèi)存 9
1.2.4 FIFO隊(duì)列 9
1.2.5 消息隊(duì)列 10
1.2.6 Socket10
1.3 CPU任務(wù)調(diào)度10
1.3.1 實(shí)時(shí)進(jìn)程與普通進(jìn)程11
1.3.2 實(shí)時(shí)調(diào)度策略11
1.3.3 普通調(diào)度策略11
1.3.4 CFS調(diào)度算法11
1.3.5 整體任務(wù)調(diào)度12
1.4 Linux線程13
1.4.1 Pthread簡介14
1.4.2 線程創(chuàng)建16
1.4.3 線程終止18
1.5 線程同步:互斥量20
1.5.1 創(chuàng)建互斥量21
1.5.2 互斥量解鎖22
1.5.3 mutex示例22
1.6 線程同步:條件變量23
1.6.1 創(chuàng)建條件變量23
1.6.2 條件變量等待24
1.6.3 條件變量通知24
1.6.4 條件變量使用示例24
1.7 線程同步:信號量25
1.7.1 初始化未命名信號量26
1.7.2 等待一個信號量26
1.7.3 發(fā)布一個信號量26
1.8 小結(jié)27
第2章 JVM基礎(chǔ)知識28
2.1 Java、JDK、JRE與JVM28
2.2 Java跨平臺原理29
2.3 JVM系統(tǒng)架構(gòu)30
2.3.1 類加載子系統(tǒng)30
2.3.2 運(yùn)行時(shí)數(shù)據(jù)區(qū)33
2.3.3 執(zhí)行引擎35
2.4 JVM與操作系統(tǒng)的線程模型36
2.4.1 操作系統(tǒng)的線程模型36
2.4.2 JVM的線程模型38
2.5 JNI機(jī)制39
2.5.1 JNI開發(fā)流程40
2.5.2 JNI數(shù)據(jù)類型轉(zhuǎn)換41
2.5.3 實(shí)現(xiàn)案例43
2.6 小結(jié)43
第3章 JVM線程44
3.1 為什么需要多線程44
3.1.1 CPU訪問各組件周期45
3.1.2 多線程的出現(xiàn)45
3.2 多線程帶來的問題46
3.2.1 CPU緩存導(dǎo)致的可見性問題46
3.2.2 線程上下文切換帶來的原子性
問題47
3.2.3 優(yōu)化帶來的亂序問題48
3.3 Java內(nèi)存模型與線程規(guī)范50
3.3.1 變量共享51
3.3.2 變量共享的內(nèi)存可見性51
3.3.3 Happens-Before規(guī)則52
3.4 內(nèi)存一致性協(xié)議56
3.4.1 CPU緩存讀取策略57
3.4.2 CPU緩存寫入策略58
3.4.3 MESI協(xié)議59
3.5 內(nèi)存屏障61
3.5.1 內(nèi)存讀寫屏障64
3.5.2 內(nèi)存屏障的實(shí)現(xiàn)64
3.5.3 JVM內(nèi)存屏障指令實(shí)現(xiàn)65
3.6 JVM的線程66
3.7 Java線程創(chuàng)建過程68
3.7.1 線程創(chuàng)建69
3.7.2 線程執(zhí)行73
3.8 Java線程生命周期75
3.8.1 Java線程生命周期模型75
3.8.2 查看線程的狀態(tài)78
3.9 小結(jié)79
第4章 JVM線程通信原理80
4.1 ParkEvent原理80
4.1.1 Allocate方法81
4.1.2 Rlease方法81
4.1.3 park方法82
4.1.4 unpark方法83
4.2 Parker實(shí)現(xiàn)原理84
4.2.1 park方法84
4.2.2 unpark方法86
4.3 sleep方法實(shí)現(xiàn)原理86
4.3.1 JVM_Sleep函數(shù)86
4.3.2 sleep函數(shù)87
4.4 ObjectMonitor實(shí)現(xiàn)原理88
4.4.1 數(shù)據(jù)結(jié)構(gòu)89
4.4.2 ObjectMonitor的構(gòu)造函數(shù)89
4.4.3 ObjectWaiter源代碼90
4.4.4 TryLock方法91
4.4.5 EnterI方法91
4.4.6 ReenterI方法93
4.4.7 enter方法94
4.4.8 exit方法?95
4.4.9 ExitEpilog方法97
4.5 wait與notify方法實(shí)現(xiàn)原理97
4.5.1 設(shè)計(jì)原理98
4.5.2 wait方法實(shí)現(xiàn)原理100
4.5.3 notify方法實(shí)現(xiàn)原理102
4.5.4 notifyAll方法實(shí)現(xiàn)原理103
4.6 yield方法實(shí)現(xiàn)原理103
4.7 join方法實(shí)現(xiàn)原理104
4.7.1 JVM_IsThreadAlive105
4.7.2 ensure_join106
4.8 stop方法實(shí)現(xiàn)原理107
4.8.1 JVM_StopThread107
4.8.2 HAS_PENDING_EXCEPTION108
4.9 interrupt方法實(shí)現(xiàn)原理109
4.10 小結(jié)110
第5章 JVM線程同步機(jī)制111
5.1 Mark Word 111
5.1.1 Mark Word詳解 112
5.1.2 hashCode驗(yàn)證113
5.1.3 輕量級鎖的狀態(tài)信息114
5.1.4 重量級鎖的狀態(tài)信息114
5.2 synchronized設(shè)計(jì)原理115
5.2.1 synchronized的使用116
5.2.2 synchronized的具體設(shè)計(jì)118
5.3 synchronized源碼分析120
5.3.1 ACC_SYNCHRONIZED解析
過程120
5.3.2 monitorenter指令解析過程122
5.3.3 monitorexit指令解析過程123
5.3.4 鎖獲取實(shí)現(xiàn)過程124
5.3.5 鎖釋放實(shí)現(xiàn)過程126
5.4 volatile實(shí)現(xiàn)原理128
5.4.1 實(shí)現(xiàn)原理概述129
5.4.2 getfield指令實(shí)現(xiàn)過程130
5.4.3 putfield指令實(shí)現(xiàn)過程131
5.5 volatile偽共享132
5.6 CAS硬件同步原語134
5.6.1 CAS硬件原語134
5.6.2 JVM CAS實(shí)現(xiàn)135
5.6.3 ABA問題135
5.7 Unsafe功能介紹136
5.7.1 操作內(nèi)存136
5.7.2 獲取字段內(nèi)存偏移量137
5.7.3 普通字段的讀取與賦值138
5.7.4 volatile字段的讀取與賦值138
5.7.5 CAS操作能力139
5.7.6 線程阻塞與喚醒139
5.7.7 內(nèi)存屏障139
5.8 Unsafe實(shí)現(xiàn)原理140
5.8.1 volatile字段讀取140
5.8.2 volatile字段寫入141
5.8.3 CAS操作能力141
5.8.4 線程阻塞與喚醒142
5.9 LockSupport實(shí)現(xiàn)原理143
5.9.1 Unsafe初始化143
5.9.2 無阻塞對象方法144
5.9.3 有阻塞對象方法144
5.9.4 線程喚醒146
5.10 小結(jié)146
進(jìn)階篇
第6章 Java鎖實(shí)現(xiàn)原理148
6.1 CPU架構(gòu)148
6.1.1 SMP148
6.1.2 NUMA149
6.1.3 SMP與NUMA比較150
6.2 自旋鎖的誕生150
6.2.1 SPIN ON TEST-AND-SET150
6.2.2 TEST-AND