1. 程式人生 > >《Effective Java》 學習筆記 —— 並發

《Effective Java》 學習筆記 —— 並發

是個 並不是 沒有 lec cached ive 而不是 線程並發 輪詢

  《Effective Java》第二版學習筆記之並發編程。

第66條 同步訪問共享的可變數據

  * 關鍵字synchronized可以保證在同一時刻只有一個線程可以執行某個方法或代碼塊。

  * Java語音規範保證對一個變量的讀操作或者寫操作是原子性(atomic,註意 i++是非原子性的,64位的long型或double型變量的讀寫操作也是非原子性的),但並不保證一個線程寫入的值對另一個線程是可見的。

  * 避免使用Thread.stop()方法,而是采用輪詢(poll)機制來終止一個線程。

  * 如果只需要線程間的交互通信,而不需要互斥,可以使用volatile關鍵字。

 

第67條 避免過度同步

  * 為了避免活性失敗和安全性失敗,在一個被同步的方法或者代碼塊中,永遠不要放棄對客戶端的控制(避免在同步區域調用不可信代碼,否則容易造成死鎖、異常等問題)。

  * 在同步代碼塊內做盡可能少的事情。

第68條 executor 和 task 優先於線程

  * Executor service 可以等待完成一項特殊的任務再繼續執行,也可以優雅的完成終止(利用awaitTerminalTermination方法),或可以在完成這些任務後逐個的獲取這些任務的結果(利用ExecutorCompletionService)等。

  * 對於輕載的服務器,Executors.newCachedThreadPool通常是個不錯的選擇;對於高負載的服務器,最好使用Executors.newFixedThreadPool

  * 盡量不要編寫自己的工作隊列和直接使用線程;現在關鍵的抽象不再是Thread,而是工作單元(任務,task)。

  * Timer只有一個線程來執行任務,如果唯一的線程拋出了未被捕獲的異常,任務就會終止。ScheduledThreadPoolExecutor 支持多個線程,並可以優雅的從拋出未受檢異常的任務中恢復。

第69條 並發工具優先於wait和notify

  * 幾乎沒有任何理由再使用wait和notify了。

    但並不是說不需要掌握,如維護舊代碼可能還是需要了解的,此種情況下務必確保是利用標準的模式從while循環內部調用wait。一般情況下優先使用notifyAll而不是notify。

  * 使用高級工具:

    執行器框架(Executor Framework)、並發集合(Concurrent Collection)、同步器(Synchronizer,如CountDownLatch、Semaphore、CyclicBarier和Exchanger等)。

第70條 線程安全性的文檔化

  * 線程安全的級別:

    (1)不可變的(immutable):類的實例是不可變的(如String、Long、BigInteger等)。

    (2)無條件的線程安全(unconditionally thread-safe):類的實例可變,但有著足夠的內部同步(如Random、ConcurrentHashMap。

    (3)有條件的線程安全(conditionally thread-safe):除了有些方法為了安全的並發使用外部同步之外,與無條件的線程安全級別相同(如 Collections.synchronized 包裝返回的集合,它們的叠代器要求外部同步)。

    (4)非線程安全(not thread-safe):需外部同步(如ArrayList、HashMap等)。

    (5)線程對立(thread hostile):這個類不能安全的被多個線程並發的使用,即使所有的方法都被外部同步包圍。線程對立的根源通常在於,沒有同步的修改靜態數據。

  * 為了避免拒絕服務攻擊,應當使用一個私有鎖對象(private lock object)來代替同步方法。私有鎖對象只能用在無條件的線程安全類上,特別適合於專門為繼承而設計的類。

第71條 慎用延遲初始化

  * 正常的初始化優先於延遲初始化。

  * 如果出於性能的考慮而需要對靜態域使用延遲初始化,就使用 lazy initiation holder class 模式:

1 private static class FieldHolder {
2     static final FieldType field = computeFieldValue();
3 }
4 
5 static FieldType getType() {
6     return FieldHolder.field;
7 }

  * 如果出於性能的考慮而需要對實例域使用延遲初始化,就使用雙重校驗鎖:

 1 // volatile 很重要,保證可見性
 2 private volatile FieldType field;
 3 
 4 FieldType getField() {
 5     FieldType result = field;
 6     if (result == null) {
 7         synchronized(this) {
 8             result = field;
 9             if (result = null) {
10                 field = result = computeFieldValue();
11             }
12         }
13     }
14     return result;  
15 }

第72條 不要依賴於線程調度器

  * 不要讓應用程序依賴線程調度器,也不要依賴 Thread.yield 或者線程優先級。這些設施僅僅對調度器作些暗示。

第73條 避免使用線程組

  * 最好把線程組當作一個不成功的實驗,就當它們根本不存在一樣。

  * 考慮使用線程池。

本文地址:https://www.cnblogs.com/laishenghao/p/9740851.html

《Effective Java》 學習筆記 —— 並發