線程安全
- 線程安全的概念:當多個線程訪問某一個類(對象和方法)時,這個類始終都能表現出正確的行為,那么這個類(對象或者方法)就是線程安全的
- synchronized:可以在任意對象及方法上加鎖,而加鎖的這段代碼稱為‘互斥區’或者“臨界區”
- 當多個線程訪問myThread的run方法時,以排隊的方式進行處理(這里排隊是按照CPU分配的先后順序而定的),一個線程想要實現synchronized裝飾的方法里的代碼,首先是嘗試獲取鎖,如果可以得到鎖,就可以執行synchronized代碼體的內容;如果拿不到鎖,這個線程就會不斷嘗試去獲取鎖資源,直到拿到為止;而且是多個線程同時去競爭這把鎖(鎖競爭)
Synchronized
- 同步Synchronized:同步的概念就是共享,如果不是共享的資源就沒有必要進行同步
- 異步asynchronized:異步的概念就是獨立,相互之間不受到任何制約
- 同步的目的是為了保證線程的安全,對于線程安全需要保證兩個特性 原子性(同步)和可見性
線程之間通信
- 線程通信的概念:線程是操作系統中獨立的個體,但是這些個體如果不經過特殊的處理就不能成為一個整體,線程之間的通信就成為整體的必用的方式之一。當線程之間存在通信指揮,系統之間的交互性會更強大,在提高CPU利用率的同時還會使開發人員對于線程任務在處理過程中,進行有效的把控和監督
- 使用wait/notify方法實現線程之間的通信(這兩個方法都是object的類的方法,即java為所有的對象都提供了這兩個方法)
- wait和notify必須配合synchronized關鍵字使用
- wait方法釋放鎖/notify方法不釋放鎖
ThreadLocal概念
- 線程局部變量,是一種多線程間并發訪問變量的解決方案,與synchronized等加鎖的方式不同,ThreadLocal完全不提供鎖,而使用以空間換時間的手段,為每個線程提供變量的獨立副本,以保障線程的安全
- 從性能上說,ThreadLocal不具有絕對的優勢,在并發不是很高的情況下,加鎖的性能可能會更好,但是作為一套與鎖完全無關的線程安全解決方案,在高并發量或者競爭激烈的場景,使用ThreadLocal可以在一定程度上減少鎖競爭
Volatile關鍵字核心概念與應用
- Volatile:主要作用是使變量在多個線程之間可見
- 阻止指令的重排序,happens-before
- 一個線程可以執行的操作有使用(use)、賦值(assign)、轉載(load)、存儲(store)、鎖定(lock)、解鎖(unlock)
- 主內存可以執行的操作有讀(read)、寫(write)、鎖定(lock)、解鎖(unlock),每個操作都是原子的
- volatile的作用就是強制線程到主內存(共享內存)里去讀取變量,而不是去線程工作內存里去讀取,從而實現了多個線程之間變量的可見,也就是滿足線程安全的可見行
JVM
- Java Memory Model(Java內存模型),簡稱JVM,用于解決線程對于共享變量的寫入何時對于另一個線程可見
- 所有變量都存儲在主內存中,每一個線程都有一個私有的本地內存,本地內存是將該線程使用到的變量,從主內存中拷貝到本地
- 線程對于變量的所有操作(讀取、賦值等)都必須在工作內存中進行,而不能直接讀寫主內存中的變量(volatile變量也不例外)
- happens-before規則,例如操作A :i=1;操作B:j=i;如果操作Ahappens-before操作B,那么操作B完成之后,j的值一定為1;
- 因為happens-before關系可以向程序員保證,在操作B執行之前,操作A的執行后的影響【或者說明結果】(修改i的值)對于操作B是可以觀察到的【可見的】
規則
- 簡而言之,使用happens-before概念來闡述操作之間的內存可見行
- 程序順序規則:一個線程中的每個操作,happens-before于該線程中的任意后續操作,也就是說,你寫的操作,如果是單線程執行,那么前面的操作就會happens-before于后面的操作
- 監視器鎖規則:對于一個鎖的解鎖,happens-before于隨后對這個鎖的加鎖
- Volatile變量規則:對于一個volatile域的寫,happens-before于任意后續對這個volatile域的讀
- 傳遞性規則:A happens-before B,B happens-before C,則A happens-before C
指令重排序
- 為了保證程序的最終運行結果需要和在單線程嚴格意義的順序化環境下執行的結果一致,程序指令的執行順序有可能和代碼的順序不一致,這個過程就稱之為指令的重排序
- 指令的重排序的意義:JVM利用處理器的特性,充分利用多級緩存,多核等進行適當的指令重排序,從而可以充分利用CPU的執行特點,最大程度上發揮機器的性能
Atomic系列類比
- Atomic系列類封裝了一系列的基礎類型和對象操作,其目的是為了實現原子性
- AtomicInteger
- AtomicLong
- AtomicBoolean
- AtomicIntegerArray
- AtomicLongArray
- AtomicReference
- 注意:在對Atomic類操作的時候,如果有多個操作執行,那么就是非原子性的,需要加aynchronized進行修飾,保證Atomic類操作的整體原子性