全書(shū)共7章。第1章講解了Java多線程的基礎(chǔ),重點(diǎn)介紹線程類(lèi)的核心API的使用。第2章講解對(duì)并發(fā)訪問(wèn)的控制,即如何寫(xiě)出線程安全的程序。第3章介紹線程間通信,以提高CPU利用率和系統(tǒng)間的交互,同時(shí)增強(qiáng)對(duì)線程任務(wù)的把控與監(jiān)督。第4章講解Lock對(duì)象,以更好實(shí)現(xiàn)并發(fā)訪問(wèn)時(shí)的同步處理。第5章講解移動(dòng)開(kāi)發(fā)中使用較多的定時(shí)器類(lèi)中的多線程技術(shù),這是計(jì)劃/任務(wù)執(zhí)行里很重要的技術(shù)點(diǎn)。第6章講解如何安全、正確地將單例模式與多線程技術(shù)相結(jié)合,避免實(shí)際應(yīng)用中可能會(huì)出現(xiàn)的麻煩。第7章將前面被遺漏的技術(shù)案例在本章節(jié)中進(jìn)行補(bǔ)充,盡量做到不出現(xiàn)技術(shù)空白點(diǎn)。
1)技術(shù)暢銷(xiāo)書(shū)全新升級(jí),案例式講解,逐一分析和驗(yàn)證每個(gè)技術(shù)點(diǎn),通俗易懂 2)本書(shū)涵蓋多線程編程的核心庫(kù)、方法、原理,解決高并發(fā)環(huán)境下的業(yè)務(wù)瓶頸
本書(shū)是國(guó)內(nèi)首本整本系統(tǒng)、完整地介紹Java多線程技術(shù)的書(shū)籍,作為筆者,我要感謝大家的支持與厚愛(ài)。
本書(shū)第1版在出版后獲得了廣大Java程序員與學(xué)習(xí)者的關(guān)注,技術(shù)論壇、博客、公眾號(hào)等平臺(tái)大量涌現(xiàn)出針對(duì)Java多線程技術(shù)的討論與分享。能為國(guó)內(nèi)IT知識(shí)的建設(shè)貢獻(xiàn)微薄之力是讓我最欣慰的。
有些讀者在第一時(shí)間就根據(jù)書(shū)中的知識(shí)總結(jié)了學(xué)習(xí)筆記,并在博客中進(jìn)行分享,筆者非常贊賞這種傳播知識(shí)的精神。知識(shí)就要分享,知識(shí)就要傳播,這樣才能共同進(jìn)步。
第2版與第1版的區(qū)別
本書(shū)第1版上市后收到了大量的讀者反饋,我對(duì)每一個(gè)建議都細(xì)心地進(jìn)行整理,力求在第2版中得以完善。
第2版在第1版的基礎(chǔ)上著重加強(qiáng)了8點(diǎn)更新:
1)大量知識(shí)點(diǎn)重排,更有利于閱讀與理解;
2)更新了讀者提出的共性問(wèn)題并進(jìn)行集中講解;
3)豐富Thread.java類(lèi)API的案例,使其更具有實(shí)用性;
4)對(duì)線程的信息進(jìn)行監(jiān)控實(shí)時(shí)采樣;
5)強(qiáng)化了volatile語(yǔ)義、多線程核心synchronized的案例;
6)力求知識(shí)點(diǎn)連貫,方便深度學(xué)習(xí)與理解,增加原子與線程安全的內(nèi)容;
7)深入淺出地介紹代碼重排特性;
8)細(xì)化工具類(lèi)ThrealLocal和InheritableThreadLocal的源代碼分析與原理。
由于篇幅有限,有關(guān)線程池的知識(shí)請(qǐng)參考筆者的另一本書(shū)《Java并發(fā)編程:核心方法與框架》,那本書(shū)中有針對(duì)Java并發(fā)編程技術(shù)的講解。在向分布式領(lǐng)域進(jìn)軍時(shí)還需要用到NIO和Socket技術(shù),故推薦筆者的拙作《NIO與Socket編程技術(shù)指南》,希望可以給讀者帶來(lái)一些幫助。
本書(shū)秉承大道至簡(jiǎn)的主導(dǎo)思想,只介紹Java多線程開(kāi)發(fā)中最值得關(guān)注的內(nèi)容,希望拋磚引玉,以個(gè)人的一些想法和見(jiàn)解,為讀者拓展出更深入、更全面的思路。
本書(shū)特色
在撰寫(xiě)本書(shū)的過(guò)程中,我盡量少用啰唆的文字,全部以Demo式案例來(lái)講解技術(shù)點(diǎn)的實(shí)現(xiàn),使讀者看到代碼及運(yùn)行結(jié)果后就可以知道項(xiàng)目要解決的是什么問(wèn)題,類(lèi)似于網(wǎng)絡(luò)中博客的風(fēng)格,讓讀者用最短的時(shí)間學(xué)習(xí)知識(shí)點(diǎn),明白知識(shí)點(diǎn)如何應(yīng)用,以及在使用時(shí)要避免什么,使讀者能夠快速學(xué)習(xí)知識(shí)并解決問(wèn)題。
讀者對(duì)象
Java程序員;
系統(tǒng)架構(gòu)師;
Java多線程開(kāi)發(fā)者;
Java并發(fā)開(kāi)發(fā)者;
大數(shù)據(jù)開(kāi)發(fā)者;
其他對(duì)多線程技術(shù)感興趣的人員。
如何閱讀本書(shū)
本書(shū)本著實(shí)用、易懂的學(xué)習(xí)原則,利用7章來(lái)介紹Java多線程相關(guān)的技術(shù)。
第1章講解了Java多線程的基礎(chǔ),包括Thread類(lèi)的核心API的使用。
第2章講解了在多線程中對(duì)并發(fā)訪問(wèn)的控制,主要是synchronized的使用。由于此關(guān)鍵字在使用上非常靈活,所以該章用很多案例來(lái)說(shuō)明它的使用,為讀者學(xué)習(xí)同步知識(shí)打好堅(jiān)實(shí)的基礎(chǔ)。
第3章講解了線程之間的通信與交互細(xì)節(jié)。該章主要介紹wait()、notifyAll()和notify()方法的使用,使線程間能夠互相通信,合作完成任務(wù)。該章還介紹了ThreadLocal類(lèi)的使用。學(xué)習(xí)完該章,讀者就能在Thread多線程中進(jìn)行數(shù)據(jù)的傳遞了。
第4章講解了Lock對(duì)象。因?yàn)閟ynchronized關(guān)鍵字使用起來(lái)比較麻煩,所以Java 5提供了Lock對(duì)象,更好地實(shí)現(xiàn)了并發(fā)訪問(wèn)時(shí)的同步處理,包括讀寫(xiě)鎖等。
第5章講解了Timer定時(shí)器類(lèi),其內(nèi)部原理是使用多線程技術(shù)。定時(shí)器在執(zhí)行計(jì)劃任務(wù)時(shí)是很重要的,在進(jìn)行Android開(kāi)發(fā)時(shí)也會(huì)深入使用。
第6章講解的單例模式雖然很簡(jiǎn)單,但如果遇到多線程將會(huì)變得非常麻煩。如何在多線程中解決這么棘手的問(wèn)題呢?本章會(huì)全面給出解決方案。
第7章對(duì)前面章節(jié)遺漏的技術(shù)空白點(diǎn)進(jìn)行補(bǔ)充,通過(guò)案例使多線程的知識(shí)體系更加完整,盡量做到不出現(xiàn)技術(shù)空白點(diǎn)。
交流和支持
由于筆者水平有限,加上編寫(xiě)時(shí)間倉(cāng)促,書(shū)中難免會(huì)出現(xiàn)一些疏漏或者不準(zhǔn)確的地方,懇請(qǐng)讀者批評(píng)指正,期待能夠得到你們的真摯反饋,在技術(shù)之路上互勉共進(jìn)。
聯(lián)系筆者的郵箱是279377921@qq.com。
致謝
在本書(shū)出版的過(guò)程中,感謝公司領(lǐng)導(dǎo)和同事的大力支持,感謝家人給予我充足的時(shí)間來(lái)撰寫(xiě)稿件,感謝出生3個(gè)多月的兒子高晟京,看到你,我有了更多動(dòng)力,最后感謝在此稿件上耗費(fèi)大量精力的高婧雅編輯與她的同事們,是你們的鼓勵(lì)和幫助,引導(dǎo)我順利完成了本書(shū)。
高洪巖
高洪巖,某世界500強(qiáng)項(xiàng)目經(jīng)理,有10年Java相關(guān)開(kāi)發(fā)經(jīng)驗(yàn),精通Java語(yǔ)言,擅長(zhǎng)J2EE、EJB、Android、報(bào)表和多線程,以及并發(fā)相關(guān)的技術(shù)內(nèi)容,理論與實(shí)踐經(jīng)驗(yàn)頗豐。著有《Java多線程編程核心技術(shù)》《Java并發(fā)編程:核心方法與框架》《NIO與Socket編程技術(shù)指南》《Java EE核心框架實(shí)戰(zhàn) 第2版》《Jasper Reports iReport報(bào)表開(kāi)發(fā)詳解》《Android學(xué)習(xí)精要》等書(shū)籍。
前言
第1章 Java多線程技能1
1.1 進(jìn)程和多線程概述1
1.2 使用多線程5
1.2.1 繼承Thread類(lèi)5
1.2.2 使用常見(jiàn)命令分析線程的信息8
1.2.3 線程隨機(jī)性的展現(xiàn)11
1.2.4 執(zhí)行start()的順序不代表執(zhí)行run()的順序12
1.2.5 實(shí)現(xiàn)Runnable接口13
1.2.6 使用Runnable接口實(shí)現(xiàn)多線程的優(yōu)點(diǎn)14
1.2.7 實(shí)現(xiàn)Runnable接口與繼承Thread類(lèi)的內(nèi)部流程16
1.2.8 實(shí)例變量共享造成的非線程安全問(wèn)題與解決方案17
1.2.9 Servlet技術(shù)造成的非線程安全問(wèn)題與解決方案21
1.2.10 留意i--與System.out.println()出現(xiàn)的非線程安全問(wèn)題24
1.3 currentThread()方法26
1.4 isAlive()方法29
1.5 sleep(long millis)方法31
1.6 sleep(long millis,
int nanos)方法33
1.7 StackTraceElement[]
getStackTrace()方法33
1.8 static void
dumpStack()方法35
1.9 static
Map getAllStackTraces()方法36
1.10 getId()方法38
1.11 停止線程38
1.11.1 停止不了的線程39
1.11.2 判斷線程是否為停止?fàn)顟B(tài)41
1.11.3 能停止的線程異常法43
1.11.4 在sleep狀態(tài)下停止線程47
1.11.5 用stop()方法暴力停止線程49
1.11.6 stop()方法與java.lang.ThreadDeath異常51
1.11.7 使用stop()釋放鎖給數(shù)據(jù)造成不一致的結(jié)果52
1.11.8 使用return;語(yǔ)句停止線程的缺點(diǎn)與解決方案54
1.12 暫停線程57
1.12.1 suspend()方法與resume()方法的使用57
1.12.2 suspend()方法與resume()方法的缺點(diǎn)獨(dú)占58
1.12.3 suspend()方法與resume()方法的缺點(diǎn)數(shù)據(jù)不完整62
1.13 yield()方法63
1.14 線程的優(yōu)先級(jí)64
1.14.1 線程優(yōu)先級(jí)的繼承特性65
1.14.2 優(yōu)先級(jí)的規(guī)律性66
1.14.3 優(yōu)先級(jí)的隨機(jī)性68
1.14.4 優(yōu)先級(jí)對(duì)線程運(yùn)行速度的影響70
1.15 守護(hù)線程71
1.16 本章小結(jié)73
第2章 對(duì)象及變量的并發(fā)訪問(wèn)74
2.1 synchronized同步方法74
2.1.1 方法內(nèi)的變量為線程安全74
2.1.2 實(shí)例變量非線程安全問(wèn)題與解決方案77
2.1.3 同步synchronized在字節(jié)碼指令中的原理80
2.1.4 多個(gè)對(duì)象多個(gè)鎖81
2.1.5 將synchronized方法與對(duì)象作為鎖84
2.1.6 臟讀89
2.1.7 synchronized鎖重入91
2.1.8 鎖重入支持繼承的環(huán)境93
2.1.9 出現(xiàn)異常,鎖自動(dòng)釋放94
2.1.10 重寫(xiě)方法不使用synchronized96
2.1.11 public static
boolean holdsLock(Object obj)方法的使用99
2.2 synchronized同步語(yǔ)句塊99
2.2.1 synchronized方法的弊端99
2.2.2 synchronized同步代碼塊的使用102
2.2.3 用同步代碼塊解決同步方法的弊端104
2.2.4 一半異步,一半同步105
2.2.5 synchronized代碼塊間的同步性108
2.2.6 println()方法也是同步的110
2.2.7 驗(yàn)證同步synchronized(this)代碼塊是鎖定當(dāng)前對(duì)象的110
2.2.8 將任意對(duì)象作為鎖113
2.2.9 多個(gè)鎖就是異步執(zhí)行116
2.2.10 驗(yàn)證方法被調(diào)用是隨機(jī)的118
2.2.11 不同步導(dǎo)致的邏輯錯(cuò)誤及其解決方法121
2.2.12 細(xì)化驗(yàn)證3個(gè)結(jié)論124
2.2.13 類(lèi)Class的單例性129
2.2.14 靜態(tài)同步synchronized方法與synchronized(class)代碼塊130
2.2.15 同步syn static方法可以對(duì)類(lèi)的所有對(duì)象實(shí)例起作用135
2.2.16 同步syn(class)代碼塊可以對(duì)類(lèi)的所有對(duì)象實(shí)例起作用137
2.2.17 String常量池特性與同步相關(guān)的問(wèn)題與解決方案138
2.2.18 同步synchronized方法無(wú)限等待問(wèn)題與解決方案141
2.2.19 多線程的死鎖143
2.2.20 內(nèi)置類(lèi)與靜態(tài)內(nèi)置類(lèi)146
2.2.21 內(nèi)置類(lèi)與同步:實(shí)驗(yàn)1149
2.2.22 內(nèi)置類(lèi)與同步:實(shí)驗(yàn)2151
2.2.23 鎖對(duì)象改變導(dǎo)致異步執(zhí)行153
2.2.24 鎖對(duì)象不改變依然同步執(zhí)行156
2.2.25 同步寫(xiě)法案例比較158
2.3 volatile關(guān)鍵字159
2.3.1 可見(jiàn)性的測(cè)試159
2.3.2 原子性的測(cè)試168
2.3.3 禁止代碼重排序的測(cè)試176
2.4 本章小結(jié)187
第3章 線程間通信188
3.1 wait/notify機(jī)制188
3.1.1 不使用wait/notify機(jī)制實(shí)現(xiàn)線程間通信188
3.1.2 wait/notify機(jī)制191
3.1.3 wait/notify機(jī)制的原理192
3.1.4 wait()方法的基本使用192
3.1.5 完整實(shí)現(xiàn)wait/notify機(jī)制194
3.1.6 使用wait/notify機(jī)制實(shí)現(xiàn)list.size()等于5時(shí)的線程銷(xiāo)毀195
3.1.7 對(duì)業(yè)務(wù)代碼進(jìn)行封裝198
3.1.8 線程狀態(tài)的切換201
3.1.9 wait()方法:立即釋放鎖202
3.1.10 sleep()方法:不釋放鎖203
3.1.11 notify()方法:不立即釋放鎖204
3.1.12 interrupt()方法遇到wait()方法206
3.1.13 notify()方法:只通知一個(gè)線程208
3.1.14 notifyAll()方法:通知所有線程211
3.1.15 wait(long)方法的基本使用212
3.1.16 wait(long)方法自動(dòng)向下運(yùn)行需要重新持有鎖214
3.1.17 通知過(guò)早問(wèn)題與解決方法217
3.1.18 wait條件發(fā)生變化與使用while的必要性220
3.1.19 生產(chǎn)者/消費(fèi)者模式的實(shí)現(xiàn)224
3.1.20 通過(guò)管道進(jìn)行線程間通信字節(jié)流250
3.1.21 通過(guò)管道進(jìn)行線程間通信字符流253
3.1.22 實(shí)現(xiàn)wait/notify的交叉?zhèn)浞?56
3.2 join()方法的使用259
3.2.1 學(xué)習(xí)join()方法前的鋪墊259
3.2.2 join()方法和interrupt()方法出現(xiàn)異常261
3.2.3 join(long)方法的使用263
3.2.4 join(long)方法與sleep(long)方法的區(qū)別264
3.2.5 join()方法后面的代碼提前運(yùn)行出現(xiàn)意外 268
3.2.6 join()方法后面的代碼提前運(yùn)行解釋意外270
3.2.7 join(long millis,
int nanos)方法的使用273
3.3 類(lèi)ThreadLocal的使用273
3.3.1 get()方法與null274
3.3.2 類(lèi)ThreadLocal存取數(shù)據(jù)流程分析275
3.3.3 驗(yàn)證線程變量的隔離性277
3.3.4 解決get()方法返回null的問(wèn)題282
3.3.5 驗(yàn)證重寫(xiě)initialValue()方法的隔離性283
3.4 類(lèi)InheritableThreadLocal的使用284
3.4.1 類(lèi)ThreadLocal不能實(shí)現(xiàn)值繼承285
3.4.2 使用InheritableThreadLocal體現(xiàn)值繼承特性286
3.4.3 值繼承特性在源代碼中的執(zhí)行流程288
3.4.4 父線程有最新的值,子線程仍是舊值291
3.4.5 子線程有最新的值,父線程仍是舊值293
3.4.6 子線程可以感應(yīng)對(duì)象屬性值的變化294
3.4.7 重寫(xiě)childValue()方法實(shí)現(xiàn)對(duì)繼承的值進(jìn)行加工297
3.5 本章小結(jié)298
第4章 Lock對(duì)象的使用299
4.1 使用ReentrantLock類(lèi)299
4.1.1 使用ReentrantLock實(shí)現(xiàn)同步299
4.1.2 驗(yàn)證多代碼塊間的同步性301
4.1.3 await()方法的錯(cuò)誤用法與更正304
4.1.4 使用await()和signal()實(shí)現(xiàn)wait/notify機(jī)制307
4.1.5 await()方法暫停線程運(yùn)行的原理309
4.1.6 通知部分線程錯(cuò)誤用法312
4.1.7 通知部分線程正確用法314
4.1.8 實(shí)現(xiàn)生產(chǎn)者/消費(fèi)者模式一對(duì)一交替輸出317
4.1.9 實(shí)現(xiàn)生產(chǎn)者/消費(fèi)者模式多對(duì)多交替輸出319
4.1.10 公平鎖與非公平鎖321
4.1.11 public int
getHoldCount()方法的使用324
4.1.12 public final int
getQueue Length()方法的使用325
4.1.13 public int
getWaitQueue-Length (Condition condition)方法的使用327
4.1.14 public final boolean
has-QueuedThread (Thread thread)方法的使用328
4.1.15 public final boolean
has-QueuedThreads()方法的使用329
4.1.16 public boolean
hasWaiters (Con-dition condition)方法的使用331
4.1.17 public final boolean
isFair()方法的使用332
4.1.18 public boolean
isHeldBy-CurrentThread()方法的使用333
4.1.19 public boolean
isLocked()方法的使用334
4.1.20 public void lockInterruptibly()方法的使用335
4.1.21 public boolean
tryLock()方法的使用336
4.1.22 public boolean
tryLock (long timeout, TimeUnit unit)方法的使用338
4.1.23 public boolean await
(long time, TimeUnit unit)方法的使用339
4.1.24 public long
awaitNanos(long nanosTimeout)方法的使用341
4.1.25 public boolean
awaitUntil(Date deadline)方法的使用342
4.1.26 public void
awaitUninterru-ptibly()方法的使用344
4.1.27 實(shí)現(xiàn)線程按順序執(zhí)行業(yè)務(wù)346
4.2 使用ReentrantReadWriteLock類(lèi)349
4.2.1 ReentrantLock類(lèi)的缺點(diǎn)349
4.2.2 ReentrantReadWriteLock類(lèi)的使用讀讀共享351
4.2.3 ReentrantReadWriteLock類(lèi)的使用寫(xiě)寫(xiě)互斥352
4.2.4 ReentrantReadWriteLock類(lèi)的使用讀寫(xiě)互斥352
4.2.5 ReentrantReadWriteLock類(lèi)的使用寫(xiě)讀互斥354
4.3 本章小結(jié)355
第5章 定時(shí)器Timer356
5.1 定時(shí)器Timer的使用356
5.1.1 schedule(TimerTask
task, Datetime)方法的測(cè)試356
5.1.2 schedule(TimerTask
task, Date firstTime, long period)方法的測(cè)試366
5.1.3 schedule(TimerTask
task, long delay)方法的測(cè)試374
5.1.4 schedule(TimerTask
task, long delay, long period)方法的測(cè)試374
5.1.5 scheduleAtFixedRate
(TimerTask task, Date firstTime, long period)方法的測(cè)試375
5.2 本章小結(jié)384
第6章 單例模式與多線程385
6.1 立即加載/餓漢模式385
6.2 延遲加載/懶漢模式387
6.2.1 延遲加載/懶漢模式解析387
6.2.2 延遲加載/懶漢模式的缺點(diǎn)388
6.2.3 延遲加載/懶漢模式的解決方案390
6.3 使用靜態(tài)內(nèi)置類(lèi)實(shí)現(xiàn)單例模式399
6.4 序列化與反序列化的單例模式實(shí)現(xiàn)400
6.5 使用static代碼塊實(shí)現(xiàn)單例模式402
6.6 使用enum枚舉數(shù)據(jù)類(lèi)型實(shí)現(xiàn)單例模式404
6.7 完善使用enum枚舉數(shù)據(jù)類(lèi)型實(shí)現(xiàn)單例模式405
6.8 本章小結(jié)407
第7章 拾遺增補(bǔ)408
7.1 線程的狀態(tài)408
7.1.1 驗(yàn)證NEW、RUNNABLE和TERMINATED410
7.1.2 驗(yàn)證TIMED_WAITING411
7.1.3 驗(yàn)證BLOCKED412
7.1.4 驗(yàn)證WAITING414
7.2 線程組415
7.2.1 線程對(duì)象關(guān)聯(lián)線程組:一級(jí)關(guān)聯(lián)416
7.2.2 線程對(duì)象關(guān)聯(lián)線程組:多級(jí)關(guān)聯(lián)417
7.2.3 線程組自動(dòng)歸屬特性418
7.2.4 獲取根線程組419
7.2.5 線程組中加線程組420
7.2.6 組內(nèi)的線程批量停止421
7.2.7 遞歸取得與非遞歸取得組內(nèi)對(duì)象422
7.3 Thread.activeCount()方法的使用423
7.4 Thread.enumerate(Thread
tarray[])方法的使用423
7.5 再次實(shí)現(xiàn)線程執(zhí)行有序性424
7.6 SimpleDateFormat非線程安全426
7.6.1 出現(xiàn)異常426
7.6.2 解決異常的方法1428
7.6.3 解決異常的方法2430
7.7 線程中出現(xiàn)異常的處理431
7.7.1 線程出現(xiàn)異常的默認(rèn)行為431
7.7.2 使用setUncaughtException-Handler()方法進(jìn)行異常處理432
7.7.3 使用setDefaultUncaughtExce-ptionHandler()方法進(jìn)行異常處理433
7.8 線程組內(nèi)處理異常434
7.9 線程異常處理的優(yōu)先性437
7.10 本章小結(jié)442