【筆記】java並發編程實戰

來源:互聯網
上載者:User

標籤:

  1. 線程帶來的問題:a)安全性問題b)活躍性問題c)效能問題
  2. 要編寫安全執行緒的代碼其核心在於要對狀態訪問操作進行管理,特別是對共用的和可變的狀態的訪問
  3. Java中的主要同步機制是關鍵字synchronized,它提供了一種獨佔的加鎖方式,”同步”這個術語還包括volatile類型的變數,顯示鎖以及原子變數
  4. 在編寫並發應用程式時,一種正確的編程方法是:首先使代碼正確運行,然後在提高代碼的速度。
  5. 完全有安全執行緒類構成的程式並不一定就是安全執行緒的,而線上程安全類中也可以包含非安全執行緒的類
  6. 執行緒安全性:當多個線程訪問某個類時,這個類始終都能表現出正確的行為,那麼就稱這個類是安全執行緒的
  7. 無狀態對象一定是安全執行緒的
  8. 無狀態對象、原子性、竟態條件、符合操作
  9. 當某個計算的正確性取決於多個線程的交替執行時序時,那麼就會發生竟態條件。最常見的竟態條件類型就是”先檢查後執行”操作,即通過一個可能失效的觀測結果來決定下一步的動作
  10. 計數器,可以通過現有的安全執行緒類實現如AtomicLong
  11. 在實際情況中,應儘可能地使用現有的安全執行緒對象(如AtomicLong)來管理類的狀態
  12. 同步代碼塊包括兩部分:一個作為鎖的對象引用,一個作為由這個鎖保護的代碼塊。
  13. 重入意味著擷取鎖的操作粒度是”線程”,而不是”調用”
  14. 每個共用的和可變的變數都應該只由一個鎖來保護,從而是維護人員知道是那一個鎖
  15. 一種常見的加鎖約定是,將所有的可變狀態都封裝在對象內部,並通過對象的內建鎖對所有訪問可變狀態的代碼路徑進行同步,使得在該對象上不會發生並發訪問,如Vector
  16. 並非所有資料都需要鎖的保護,只有被多個線程同時訪問的可變資料才需要通過鎖來保護
  17. 對於每個包含多個變數的不可變性條件,其中涉及的所有變數都需要由同一個鎖來保護
  18. 無論是執行計算密集的操作,還是在執行某個可能阻塞的操作,如果持有鎖的時間過長,那麼都會帶來活躍性或效能問題,當執行時間較長的計算或者可能無法快速完成的操作時(如I/O),一定不要持有鎖
  19. 只要有資料在多個線程間共用,就使用正確的同步
  20. 可見度問題,產生失效值,非原子的64位操作問題,使用volatile聲明或同步保護
  21. 當把變數聲明為volatile類型後,編譯器與運行時都會注意到這個變數是共用的,因此不會將該變數上的操作與其他記憶體操作一起重排序。
  22. Volatile變數的正確的使用方式包括:確保它們自身狀態的可見度,確保它們所引用對象的狀態的可見度,以及標識一些重要的程式生命週期事件的發生(例如,初始化或關閉)
  23. 調試提示,在啟動JVM時指定 –servcr命令,將進行更多最佳化,比如將迴圈中未被修改的變數提升到迴圈外部,發現無線迴圈
  24. 加鎖機制既可以確保可見度又可以確保原子性,而volatile變數只能確保可見度
  25. 若且唯若滿足一下所有條件時,才應該使用volatile變數:a)對變數的寫入操作不依賴變數的當前值,或者能確保只有單個線程更新變數的值b)該變數不會與其他狀態變數一起納入不變性條件中c)在訪問變數時不需要加鎖
  26. 當訪問共用的可變資料時,通常需要使用同步。一種避免使用同步的方式就是不共用資料。如果僅在單線程內訪問資料,就不需要同步。這種技術被稱為線程封閉
  27. 線程封閉技術:Ad-hoc/棧封閉/ThreadLocal類
  28. 滿足同步需求的另一種方法是使用不可變對象:某個對象在被建立後其狀態就不能被修改。不可變對象只有一種狀態,且有建構函式來控制
  29. 不可變:a)狀態不可修改b)所有域都是final類型c)正確的構造過程
  30. 可變對象必須通過安全的方式來發布,這通常意味著在發布和使用該對象的線程時都必須使用同步
  31. 要安全地發布一個對象,對象的引用以及對象的狀態必須同時對其他線程可見。一個正確構造的對象可以通過以下方式來安全的發布:a)在靜態初始化函數中初始化一個對象引用b)將對象的引用儲存到volatile類型的域或者AtomicReferance對象中c)將對象的引用儲存到某個正確構造對象的final類型域中d)將對象的引用儲存到一個由鎖保護的域中
  32. 通過容器安全發布對象:a)通過將一個鍵或者值放入Hashtable、synchronizedMap或者ConcurrentMap中b)通過將某個元素放入Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、synchronizedList或synchronizedSet中c)通過將某個元素放入BlockingQuere或者ConcurrentLinkedQuere中
  33. 當獲得對象的一個引用時,需要知道在這個引用上可以執行哪些操作。在使用它之前是否需要獲得一個鎖,是否可以修改它的狀態,或者只能讀取它
  34. 在並發程式中使用和共用對象時,可以使用一些實用的策略:a)線程封閉b)唯讀共用c)安全執行緒共用d)保護對象
  35. 在設計安全執行緒類的過程中,需要包含一下三個基本要素:a)找出構成對象狀態的所有變數b)找出約束狀態變數的不變性條件c)建立對象狀態的並發訪問管理原則
  36. 等待某個條件為真的各種內建機制(包括等待和通知等機制)都與內建加鎖機制緊密關聯
  37. 將資料封裝在對象內部,可以將資料的訪問限制在對象的方法上,從而更容易確保線程在訪問資料時總能持有正確的鎖
  38. 使用私人的鎖對象而不是對象的內建鎖(或任何其他可通過公有方式訪問的鎖),可以將鎖封裝起來,使客戶代碼無法得到鎖,但客戶代碼可以通過共有方法來訪問鎖
  39. 如果一個狀態變數是安全執行緒的,並且沒有任何不變性條件來約束它的值,在變數的操作上也不存在任何不允許的狀態轉換,那麼就可以安全的發布這個變數
  40. Synchronized、volatile或者任何一個安全執行緒類都對應於某種同步策略,用於在並發訪問時確保資料的完整性
  41. 在設計同步策略時需要考慮多個方面,例如,將哪些變數聲明為volatile類型,哪些變數用鎖來保護,哪些鎖保護那些變數,哪些變數必須是不可變的或者被封閉線上程中的,哪些操作必須是原子操作等。
  42. servletContext、Httpsession或dataSource等的執行緒安全性
  43. 同步容器將所有對容器狀態的訪問都穿行化,以實現它們的執行緒安全性。這種方法的代價是嚴重降低並發性,當多個線程競爭容器的鎖時,輸送量將嚴重減低
  44. 通過並發容器來代替同步容器,可以極大的提高伸縮性並降低風險;ConcurrentHashMap、CopyOnWriteArrayList、CopyonWriteArraySet、BlockingQueue
  45. 阻塞隊列可以作為同步工具類,其他類型的同步工具類還包括訊號量(Semaphore)、柵欄(Barrier)以及閉鎖(Latch)
  46. 閉鎖可以延遲線程的進度直到其到達終止狀態,可以用來確保某些活動直到其他活動都完成偶才繼續執行
  47. FutureTask表示的計算是通過Callable來實現的,相當於一種可產生結果的Runnable,FutureTask在Executor架構中表示非同步任務,此外還可以用來表示一些時間較長的計算
  48. 計數訊號量用來控制同時訪問某個特定資源的運算元量,或者同時執行某個指定操作的數量,可以用於實現資源集區,例如資料庫連接池
  49. 柵欄類似於閉鎖,它能阻塞一組線程直到某個事件發生。柵欄與閉鎖的關鍵區別在於,所有線程必須同時到達柵欄位置,才能繼續執行,閉鎖用於等待事件,而柵欄用於等待其他線程
  50. 並發技巧:a)可變狀態是至關重要的b)盡量將域聲明為final類型,除非需要它們是可變的c)不可變對象一定是安全執行緒的d)封裝有助於管理複雜性e)用鎖來保護每個可變變數f)當保護同一個不變性條件中的所有變數時,要使用同一個鎖g)在執行複合操作期間,要持有鎖h)如果從多個線程中訪問同一個可變變數時沒有同步機制,那麼程式會出現問題i)不要故作聰明的推斷出不需要使用同步j)在設計過程中考慮安全執行緒,或者在文檔中明確地指出它不是安全執行緒的k)將同步策略文檔化
  51. 線上程池中執行任務比為每個任務分配一個線程優勢更多:a)重用線程,分攤線上程建立和銷毀過程中產生的巨大開銷b)請求到達時,背景工作執行緒已存在,不會由於等待建立線程而延遲任務的執行,提高了響應性c)通過調整線程池大小,可以建立足夠多的線程以便使處理器保持忙碌狀態,同時還可以防止過多線程相互競爭資源而使應用程式耗盡記憶體或失敗
  52. 通過使用Executor,可以實現各種調優、管理、監視、記錄日誌、錯誤報表和其他功能,如果不使用任務執行架構,那麼要增加這些功能是很困難的
  53. Executor架構將任務提交與執行策略解耦開來,同時還支援多種不同類型的執行策略。當需要建立線程來執行任務時,可以考慮使用Executor
  54. 在java中沒有一種安全的搶佔式方法來停止線程,因此也就沒有安全的搶佔式方法來停止任務。只有一些協作式的機制,使請求取消的任務和代碼都遵循一種協商好的協議:a)”已請求取消”標誌
  55. 對中斷操作的正確理解是:它並不會真正地中斷一個正在啟動並執行線程,而只是發出插斷要求,然後由線程在下一個合適的時刻中斷自己(這些時刻也被稱為取消點),通常,中斷是實現取消的最合理方式
  56. 最合理的中斷策略是某種形式的線程級(Thread-Level)取消操作或服務級(Service-Level)取消操作:儘快退出,在必要時進行清理,通知某個所有者線程已經退出
  57. 任務不會在其自己擁有的線程中執行,而是在某個服務(如線程池)擁有的線程中執行,這就是大多數可阻塞的庫函數都只是拋出interruptedException作為中斷響應,它們永遠不會在某個由自己擁有的線程中運行,因此它們為任務或庫代碼實現了最合理的取消策略:儘快退出執行流程,並把中斷資訊傳遞給調用者,從而使調用棧中的上層代碼可以採取進一步的操作
  58. 當取消一個生產者-消費者操作時,需要同時取消生產者和消費者
  59. 關閉鉤子是指通過Runtime.addShutdownHook註冊的但尚未開始的線程
  60. 線程可分為兩種:普通線程和守護線程。在JVM啟動時建立的所有線程中,除了主線程以外,其他的線程都是守護線程(例如記憶體回收行程以及其他執行輔助工作的線程)。當建立一個新線程時,新線程將繼承它的線程的守護狀態,因此在預設情況下,主線程建立的所有線程都是普通線程。普通線程與守護線程之間的差異僅在於當線程退出時發生的操作
  61. 死結:過度加鎖可能導致”鎖順序死結”,使用線程池和訊號量來限制對資源的使用,可能會導致”資源死結”
  62. 在並發程式中,對延展性的最主要威脅就是獨佔方式的資源鎖
  63. 有兩個因素將影響在鎖上發生競爭的可能性:鎖的請求頻率,以及每次持有該鎖的時間
  64. Amdahl定律告訴我們,程式的延展性取決於在所有代碼中必須被串列執行的代碼比例
  65. 提升延展性可通過:減少鎖的持有時間,降低鎖的粒度,以及採用非獨佔的鎖或非阻塞鎖來代替獨佔鎖
  66. 當某個類第一次被載入時,JVM會通過解釋位元組碼的方式來執行它。在某個時刻,如果一個方法啟動並執行次數足夠多,那麼動態編譯器會將它編譯為機器代碼,當編譯完成後,代碼的執行方式將從解釋執行變為直接執行
  67. 當持有鎖的時間相對較長,或者請求鎖的平均時間間隔較長,那麼應該使用公平鎖。在這些情況下,”插隊”帶來的輸送量提升則可能不會出現
  68. 在一些內建鎖無法滿足需求的情況下,ReentrantLock可以作為一種進階工具。當需要一些進階功能時才應該使用ReentrantLock,這些功能包括:可定時的、可輪詢的與可中斷的鎖擷取操作,公平隊列,以及非塊結構的鎖。否則,還是應該優先使用synchronized
  69. 讀/寫鎖:一個資源可以被多個讀操作訪問,或者被一個寫操作訪問,但兩者不能同時進行
  70. 可以使用java語言和類庫提供的底層機制來構造自己的同步機制,包括內建的條件隊列、顯示的Condition對象以及AbstractQueuedSynchronized架構
  71. 當使用條件等待時(Object.wait或Condition.await):a)通產都有一個條件謂詞-包括一些對象狀態的測試,線程在執行前必須首先通過這些測試b)在調用wait之前測試條件謂詞,並且從wait中返回時再次進行測試c)在一個迴圈中調用wait d)確保使用與條件隊列相關的鎖來保護構成條件謂詞的各個狀態變數e)當調用wait、notify或notifyAll等方法時,一定要持有與條件隊列相關的鎖f)在檢查條件謂詞之後以及開始執行相應的操作之前,不要釋放鎖
  72. 活躍性故障:死結、活鎖、丟失的訊號。丟失的訊號:線程必須等待一個已經為真的條件,但在開始等待之前沒有檢查條件謂詞
  73. 大多數情況下應該有限選擇notifyAll而不是單個的notify。只有同時滿足兩個條件時,才能用單一的notify而不是notifyAll:a)所有等待線程的類型都相同,只有一個條件謂詞與條件隊列相關,並且每個線程在從wait返回後將執行相同的操作b)單進單出,在條件變數上的每次通知,最多隻能喚醒一個線程來執行
  74. 對於每個依賴狀態的操作,以及每個修改其他動作依賴狀態的操作,都應該定義一個入口協議和出口協議,入口協議就是該操作的條件謂詞,出口協議則包括:檢查被該操作修改的所有狀態變數,並確認它們是否使用某個其他的條件謂詞變為真,如果是,則通知相關的條件隊列

 

【筆記】java並發編程實戰

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.