商品簡介
在單核CPU時代,單任務在一個時間點只能執行單一程序,隨著多核CPU的發展,並行程序開發變得尤為重要。本書主要介紹基於Java的並行程序設計基礎、思路、方法和實戰。第一,立足於併發程序基礎,詳細介紹Java進行並行程序設計的基本方法。第二,進一步詳細介紹了JDK對並行程序的強大支持,幫助讀者快速、穩健地進行並行程序開發。第三,詳細討論了“鎖”的優化和提高並行程序性能級別的方法和思路。第四,介紹了並行的基本設計模式,以及Java 8/9/10對並行程序的支持和改進。第五,介紹了高併發框架Akka的使用方法。第六,詳細介紹了並行程序的調試方法。第七,分析Jetty代碼並給出一些其在高併發優化方面的例子。本書內容豐富,實例典型,實用性強,適合有一定Java基礎的技術開發人員閱讀。
序
前 言
關於Java與並行
由於單核CPU的主頻逐步逼近極限,多核CPU架構成了一種必然的技術趨勢,因此多線程並行程序便顯得越來越重要。並行計算的一個重要應用場景就是服務端編程。目前服務端CPU的核心數已經輕鬆超越10個,而Java顯然已經成為當下最流行的服務端編程語言,且已經更新到JDK 10,因此熟悉和瞭解基於Java的並行程序開發有著重要的實用價值。
本書的體系結構
本書立足于實際開發,又不缺乏理論介紹,力求通俗易懂、循序漸進。本書共分為9章。
第1章主要介紹了並行計算中相關的一些基本概念,樹立讀者對並行計算的基本認識,介紹了兩個重要的並行性能評估定律,以及Java內存模型JMM。
第2章介紹了Java並行程序開發的基礎,包括Java中Thread的基本使用方法等,也詳細介紹了並行程序容易引發的一些錯誤,以及容易出現的誤用。
第3章介紹了JDK內部對並行程序開發的支持,主要介紹juc(java.util.concurrent)中一些工具的使用方法、各自的特點及它們的內部實現原理。
第4章介紹了在開發過程中可以進行的對鎖的優化,也進一步簡要描述了Java虛擬機層面對並行程序的優化支持。此外,還花費一定的篇幅介紹了無鎖的計算。
第5章介紹了並行程序設計中常見的一些設計模式,以及一些典型的並行算法和使用方法,其中包括重要的Java NIO和AIO的介紹。
第6章介紹了Java 8/9/10為並行計算做的改進,包括並行流、CompletableFuture、StampedLock、LongAdder,以及發佈和訂閱模式等。
第7章主要介紹了高併發框架Akka的基本使用方法,並使用Akka框架實現了一個簡單的粒子群算法,模擬超高併發的場景。
第8章介紹了使用Eclipse進行多線程調試的方法,並演示了通過Eclipse進行多線程調試重現ArrayList的線程不安全問題。
第9章介紹了Jetty,並分析了Jetty的一些關鍵代碼,主要展示它在高併發優化中所做的一些努力,也為讀者學會並深入理解高併發帶來一些提示和思考。
本書特色
本書的主要特色如下。
1. 結構清晰。本書一共9章,總體上循序漸進,逐步提升。每一章都有鮮明的側重點,有利於讀者快速抓住重點。
2. 理論結合實戰。本書注重實戰,書中重要的知識點都安排了代碼實例,幫助讀者理解。同時也不忘對系統的內部實現原理進行深度剖析。
3. 通俗易懂。本書儘量避免採用過於理論化的描述方式,簡單的白話文風格貫穿全書,配圖基本上為手工繪製,降低了理解難度,並儘量做到讀者在閱讀過程中少盲點、無盲點。
適合閱讀人群
雖然本書力求通俗,但是要通讀本書並取得良好的學習效果,要求讀者具備基本的Java知識或者一定的編程經驗。因此,本書適合以下讀者。
? 擁有一定開發經驗的Java平臺開發人員(Java、Scala、JRuby等)。
? 軟件設計師、架構師。
? 系統調優人員。
? 有一定的Java編程基礎並希望進一步加深對並行程序的理解的研發人員。
本書的約定和更新
本書在敘述過程中,有如下約定。
? 本書所述的JDK 1.5、JDK 1.6、JDK 1.7、JDK 1.8、JDK 1.9、JDK 1.10分別等同於JDK 5、JDK 6、JDK 7、JDK 8、JDK 9、JDK 10。
? 如無特殊說明,本書的程序、示例均在JDK 1.8以上環境中運行。
相較前一版,本書的主要更新如下。
1. 第3章增加的內容如下。
? 使用JMH進行性能測試。
? CopyOnWriteArrayList ConcurrentLinkedQueue性能測試。
? 使用Guava的RateLimiter限流。
? Guava中對線程池的擴展。
? 介紹JDK中ArrayBlockingQueue的算法。
2. 第5章增加的內容如下。
? Guava對Future模式的支持。
3. 第6章增加的內容如下。
? 支持timeout的CompletableFuture。
? ConcurrentHashMap在新版本JDK中的增強。
? 發佈和訂閱模式。
4. 增加第9章,主要介紹Jetty多線程優化。從細節入手分析Jetty在多線程併發方面做出的努力和優化,對實踐應用具有極強的參考價值。
聯繫作者
本書的寫作過程遠比我想像得艱辛,為了讓全書能夠更清楚、更準確地表達和論述,我經歷了很多個不眠之夜,即使現在回想起來,我也忍不住會打個寒戰。由於寫作水平的限制,書中難免會有不妥之處,望讀者諒解。
為此,如果讀者有任何疑問或者建議,非常歡迎大家加入QQ群254693571,一起探討學習中的困難、分享學習經驗,我期待與大家一起交流、共同進步。同時,大家也可以關注我的博客http://www.uucode.net/。歡迎大家去博文視點社區下載本書推薦的參考文獻。
感謝
本書能夠面世,是因為得到了眾人的支持。首先,要感謝我的妻子,她始終不辭辛勞、毫無怨言地對我照顧有加,才讓我得以騰出大量時間安心工作。其次,要感謝所有編輯為我一次又一次地審稿改錯,批評指正,促進本書逐步完善。最後,感謝我的母親三十年如一日對我的體貼和關心。
葛一鳴
讀者服務
輕鬆註冊成為博文視點社區用戶(www.broadview.com.cn),您即可享受以下服務:
? 下載資源:本書如提供示例代碼及資源文件,均可在 下載資源 處下載。
? 提交勘誤:您對書中內容的修改意見可在 提交勘誤 處提交,若被採納,將獲贈博文視點社區積分(在您購買電子書時,積分可用來抵扣相應金額)。
? 與作者交流:在頁面下方 讀者評論 處留下您的疑問或觀點,與作者和其他讀者一同學習交流。
頁面入口:http://www.broadview.com.cn/35003
目次
目 錄
第1章 走入並行世界 1
1.1 何去何從的並行計算 1
1.1.1 忘掉那該死的並行 2
1.1.2 可怕的現實:摩爾定律的失效 4
1.1.3 柳暗花明:不斷地前進 5
1.1.4 光明或是黑暗 6
1.2 你必須知道的幾個概念 7
1.2.1 同步(Synchronous)和異步(Asynchronous) 7
1.2.2 併發(Concurrency)和並行(Parallelism) 8
1.2.3 臨界區 9
1.2.4 阻塞(Blocking)和非阻塞(Non-Blocking) 9
1.2.5 死鎖(Deadlock)、饑餓(Starvation)和活鎖(Livelock) 10
1.3 併發級別 11
1.3.1 阻塞 11
1.3.2 無饑餓(Starvation-Free) 11
1.3.3 無障礙(Obstruction-Free) 12
1.3.4 無鎖(Lock-Free) 13
1.3.5 無等待(Wait-Free) 13
1.4 有關並行的兩個重要定律 14
1.4.1 Amdahl定律 14
1.4.2 Gustafson定律 16
1.4.3 是否相互矛盾 17
1.5 回到Java:JMM 18
1.5.1 原子性(Atomicity) 18
1.5.2 可見性(Visibility) 20
1.5.3 有序性(Ordering) 22
1.5.4 哪些指令不能重排:Happen-Before規則 27
第2章 Java並行程序基礎 29
2.1 有關線程你必須知道的事 29
2.2 初始線程:線程的基本操作 32
2.2.1 新建線程 32
2.2.2 終止線程 34
2.2.3 線程中斷 38
2.2.4 等待(wait)和通知(notify) 41
2.2.5 掛起(suspend)和繼續執行(resume)線程 45
2.2.6 等待線程結束(join)和謙讓(yeild) 49
2.3 volatile與Java內存模型(JMM) 50
2.4 分門別類的管理:線程組 53
2.5 駐守後臺:守護線程(Daemon) 54
2.6 先做重要的事:線程優先級 56
2.7 線程安全的概念與關鍵字synchronized 57
2.8 程序中的幽靈:隱蔽的錯誤 61
2.8.1 無提示的錯誤案例 62
2.8.2 併發下的ArrayList 63
2.8.3 併發下詭異的HashMap 64
2.8.4 初學者常見的問題:錯誤的加鎖 67
第3章 JDK並發包 71
3.1 多線程的團隊協作:同步控制 71
3.1.1 關鍵字synchronized的功能擴展:重入鎖 72
3.1.2 重入鎖的好搭檔:Condition 81
3.1.3 允許多個線程同時訪問:信號量(Semaphore) 85
3.1.4 ReadWriteLock讀寫鎖 86
3.1.5 倒計數器:CountDownLatch 89
3.1.6 循環柵欄:CyclicBarrier 91
3.1.7 線程阻塞工具類:LockSupport 94
3.1.8 Guava和RateLimiter限流 98
3.2 線程複用:線程池 101
3.2.1 什麼是線程池 102
3.2.2 不要重複發明輪子:JDK對線程池的支持 102
3.2.3 刨根究底:核心線程池的內部實現 108
3.2.4 超負載了怎麼辦:拒絕策略 112
3.2.5 自定義線程創建:ThreadFactory 115
3.2.6 我的應用我做主:擴展線程池 116
3.2.7 合理的選擇:優化線程池線程數量 119
3.2.8 堆棧去哪裡了:在線程池中尋找堆棧 120
3.2.9 分而治之:Fork/Join框架 124
3.2.10 Guava中對線程池的擴展 128
3.3 不要重複發明輪子:JDK的併發容器 130
3.3.1 超好用的工具類:併發集合簡介 130
3.3.2 線程安全的HashMap 131
3.3.3 有關List的線程安全 132
3.3.4 高效讀寫的隊列:深度剖析ConcurrentLinkedQueue類 132
3.3.5 高效讀取:不變模式下的CopyOnWriteArrayList類 138
3.3.6 數據共享通道:BlockingQueue 139
3.3.7 隨機數據結構:跳表(SkipList) 144
3.4 使用JMH進行性能測試 146
3.4.1 什麼是JMH 147
3.4.2 Hello JMH 147
3.4.3 JMH的基本概念和配置 150
3.4.4 理解JMH中的Mode 151
3.4.5 理解JMH中的State 153
3.4.6 有關性能的一些思考 154
3.4.7 CopyOnWriteArrayList類與ConcurrentLinkedQueue類 157
第4章 鎖的優化及注意事項 161
4.1 有助於提高鎖性能的幾點建議 162
4.1.1 減少鎖持有時間 162
4.1.2 減小鎖粒度 163
4.1.3 用讀寫分離鎖來替換獨佔鎖 165
4.1.4 鎖分離 165
4.1.5 鎖粗化 168
4.2 Java虛擬機對鎖優化所做的努力 169
4.2.1 鎖偏向 169
4.2.2 輕量級鎖 169
4.2.3 自旋鎖 170
4.2.4 鎖消除 170
4.3 人手一支筆:ThreadLocal 171
4.3.1 ThreadLocal的簡單使用 171
4.3.2 ThreadLocal的實現原理 173
4.3.3 對性能有何幫助 179
4.4 無鎖 182
4.4.1 與眾不同的併發策略:比較交換 182
4.4.2 無鎖的線程安全整數:AtomicInteger 183
4.4.3 Java中的指針:Unsafe類 185
4.4.4 無鎖的對象引用:AtomicReference 187
4.4.5 帶有時間戳的對象引用:AtomicStampedReference 190
4.4.6 數組也能無鎖:AtomicIntegerArray 193
4.4.7 讓普通變量也享受原子操作:AtomicIntegerFieldUpdater 194
4.4.8 挑戰無鎖算法:無鎖的Vector實現 196
4.4.9 讓線程之間互相幫助:細看SynchronousQueue的實現 201
4.5 有關死鎖的問題 205
第5章 並行模式與算法 209
5.1 探討單例模式 209
5.2 不變模式 213
5.3 生產者-消費者模式 215
5.4 高性能的生產者-消費者模式:無鎖的實現 220
5.4.1 無鎖的緩存框架:Disruptor 221
5.4.2 用Disruptor框架實現生產者-消費者模式的案例 222
5.4.3 提高消費者的響應時間:選擇合適的策略 225
5.4.4 CPU Cache的優化:解決偽共享問題 226
5.5 Future模式 230
5.5.1 Future模式的主要角色 232
5.5.2 Future模式的簡單實現 233
5.5.3 JDK中的Future模式 236
5.5.4 Guava對Future模式的支持 238
5.6 並行流水線 240
5.7 並行搜索 244
5.8 並行排序 246
5.8.1 分離數據相關性:奇偶交換排序 246
5.8.2 改進的插入排序:希爾排序 250
5.9 並行算法:矩陣乘法 254
5.10 準備好了再通知我:網絡NIO 258
5.10.1 基於Socket的服務端多線程模式 259
5.10.2 使用NIO進行網絡編程 264
5.10.3 使用NIO來實現客戶端 272
5.11 讀完了再通知我:AIO 274
5.11.1 AIO EchoServer的實現 275
5.11.2 AIO Echo客戶端的實現 277
第6章 Java 8/9/10與併發 281
6.1 Java 8的函數式編程簡介 281
6.1.1 函數作為一等公民 282
6.1.2 無副作用 283
6.1.3 聲明式的(Declarative) 283
6.1.4 不變的對象 284
6.1.5 易於並行 284
6.1.6 更少的代碼 284
6.2 函數式編程基礎 285
6.2.1 FunctionalInterface注釋 285
6.2.2 接口默認方法 286
6.2.3 lambda表達式 290
6.2.4 方法引用 291
6.3 一步一步走入函數式編程 293
6.4 並行流與並行排序 298
6.4.1 使用並行流過濾數據 298
6.4.2 從集合得到並行流 299
6.4.3 並行排序 299
6.5 增強的Future:CompletableFuture 300
6.5.1 完成了就通知我 300
6.5.2 異步執行任務 301
6.5.3 流式調用 303
6.5.4 CompletableFuture中的異常處理 303
6.5.5 組合多個CompletableFuture 304
6.5.6 支持timeout的 CompletableFuture 306
6.6 讀寫鎖的改進:StampedLock 306
6.6.1 StampedLock使用示例 307
6.6.2 StampedLock的小陷阱 308
6.6.3 有關StampedLock的實現思想 310
6.7 原子類的增強 313
6.7.1 更快的原子類:LongAdder 314
6.7.2 LongAdder功能的增強版:LongAccumulator 320
6.8 ConcurrentHashMap的增強 321
6.8.1 foreach操