Java多線程——多線程相關知識的邏輯關係梳理

1 學習多線程知識的根本目標

       多線程知識的根本目標是:設計穩健的併發程序。
       固然,本文沒法回答這個實踐性很強的問題(這與具體的業務相關,涉及到具體的策略),本文主要闡述相關知識之間的關係,但願初學者不要迷失在多線程工具類的API接口中。緩存

2 併發程序的三大宏觀問題

       線程安全性問題、性能問題、活躍性問題。 三者的關係是,在設計併發程序過程當中要首先保證線程安全,在線程安全的基礎上努力提高程序性能,在保證線程安全與提高性能時避免引入活躍性問題。
       線程安全是最重要的,設計併發程序是爲了提高程序的性能,可是永遠不要忘記性能是創建在安全的基礎上的;而在保證安全性(如加鎖、同步等方法)及優化併發性能(如經過鎖分解、鎖分段等方法)過程當中,可能會引入活躍性問題(如死鎖、飢餓、活鎖、糟糕的響應性等問題)。 本文主要闡述線程安全問題的知識。安全

3 線程安全性

3.1 線程安全性的定義

       當多個線程訪問某個類時,這個類始終都能表現出正確行爲,那麼就稱這個類是線程安全的。最核心的概念就是正確性。正確性的含義是,某個類的行爲與其規範徹底一致。
       就像你要設計一道菜,那麼組成這道菜的食材和調料必定是可控的,即你能確切的描述對這些食材和調料操做的結果,好比放油菜會香,放鹽菜會鹹,而且知道菜快熟時再放鹽,只有對構成這道菜的全部元素都清楚明晰,設計出的菜才符合設想。設計程序時也同樣,只有使用的各個變量和函數是可控的,設計出的程序才能按照設計運行。而多線程的使用,可能會使得組成程序的某些變量和行爲變得不可控多線程

3.2 爲何多線程會帶來線程安全性問題

       要闡明線程安全性問題須要深刻到JAVA內存模型,這裏暫時不引入,這裏用兩個生活中的例子來闡述線程安全性問題的本質(原子性問題和可見性問題)。
例1】以炒菜爲例。其中有個操做是放鹽,放鹽的操做可分解爲三個步驟「找到鹽罐→檢查鹽罐裝的是鹽→菜快熟的時候將鹽倒入菜中」。若是隻有一我的在使用鹽罐,那麼不會有什麼問題。可是,若是在你「檢查鹽罐中裝的是鹽」以後,將鹽倒入菜中以前,另外一我的拿走了鹽罐,裝了三氯氰胺奶粉,而後將鹽罐放回。這個調換過程你並不知道,最後你將調換過的三氯氰胺奶粉倒入了菜中,結果可想而知。這就是線程安全性問題的原子性問題
從內存模型理解原子性問題juejin.im/post/5d7760…併發

例2】以A和B協做煮米飯爲例。有三個房間(廚房、控火室、觀察室),廚房有個鍋煮着米飯(鍋上有張紙寫着「已熟」或者「未熟」),A在控火室負責關火(當看到鍋上的紙寫着「已熟」時關火),B在觀察室負責觀察米的狀態並修改鍋上貼紙的狀態字(已熟/未熟);A和B不在一個房間,沒法直接交流;B隔一會觀察下鍋裏的米,若是米熟了就在一張紙上寫「已熟」,未熟就寫「未熟」,B很忙,寫完字後將紙貼在了本身門上,未貼在廚房的鍋上。最終結果是,A看到鍋上的狀態字一直是「未熟」,因此不關火,最終米飯糊了。這就是可見性問題
從內存模型理解可見性問題juejin.im/post/5d7760…函數

3.3 解決原子性問題和內存可見性的核心

       要編寫線程安全的代碼,其核心在於要對狀態(變量)訪問操做進行管理,特別是對共享的可變的狀態的訪問。
       共享意味着可由多個線程訪問操做,可變意味着能夠被修改。
       上述例1中,若是鹽罐不共享即其餘人不能使用,則不會有線程安全性問題。若是規定不能往鹽罐中裝入,只能從鹽罐中取出,那麼無論多少我的能夠操做鹽罐,鹽罐中始終是鹽,沒有線程安全性問題;一樣,若是一個變量不能被修改,那麼無論多少個線程操做這個變量,也不會帶來線程安全性問題。
       上述例2中,若是強制B在修改狀態字後,將紙貼在鍋上,那麼就可讓A看到米飯的真正狀態,就能夠及時關掉火,蒸出香噴噴的米飯。工具

       那麼,爲了解決原子性問題和內存可見性問題,怎麼對共享的且可變的變量進行管理?post

  • 除非須要某個域是可變的,不然應將其聲明爲final域(即聲明爲不可變的)
  • 將對共享變量的並行操做轉換爲串行操做(如同步機制、將變量委託給同步容器進行管理)
  • 將共享變量轉換爲不共享變量(如線程封閉(棧封閉、ThreadLocal類等))
  • 若是某個操做須要以原子方式執行,那麼就想辦法保證這個操做是原子方式執行(如給操做加鎖)
  • 對於須要保證內存可見性的變量,能夠強制線程從主內存而不是緩存中讀取變量,在線程存儲變量時強制存取到主內存中。(如加鎖,聲明volatile變量)

切記,核心是管理共享的可變狀態,鎖(內置鎖、Lock鎖)、同步容器類(Vector、Hashtable等)、併發容器類(ConcurrentHashMap、CopyOnWriteArrayList)、同步工具類(閉鎖、信號量、柵欄)、線程池等都只是是管理共享的可變狀態的工具。性能

相關文章
相關標籤/搜索