執行緒安全問題的產生條件、解決方式
- 2022 年 9 月 25 日
- 筆記
- 執行緒安全問題的產生條件、解決方式
1、執行緒安全的產生條件
■ 執行緒安全問題概念:
多個執行緒在並發下執行,對共享數據進行訪問,造成執行結果 不一致 的情況。
- 執行緒安全產生前提: 存在多個執行緒、並發執行(執行緒之間處於爭搶資源的競爭狀態)、 共享數據
- 執行緒不安全造成的結果:
數據不一致
執行緒安全結果:數據一致;執行緒不安全結果:數據不一致
執行緒安全問題:就是執行緒不安全導致的問題
■ 並發、並行
-
並發(多個執行緒操作同一個資源)
- CPU 一核,模擬出多條執行緒, CPU 快速交替實現 ,多個執行緒之間處於競爭關係,爭搶資源
-
並發(多個人一個起走)
- CPU 多核,多個執行緒可以同時執行,執行緒池
2、解決執行緒安全的方式
解決思路:破解產生的三個條件即可
比如使用單執行緒;對共享數據處理【比如數據類型是不變的、已知的執行緒安全的變數(執行緒安全集合Vector、原子操作類Atomic等)、執行緒私有的變數等】;對並發處理為同步【比如互斥同步、非阻塞同步】
- 同步是指在多個執行緒並發訪問共享數據時,保證共享數據在同一個時刻只被一條執行緒使用。
■ 常見的執行緒安全的解決方式
(1) 加鎖方式
- 使用 同步關鍵詞 synchronized 或者 lock 的子類可重入鎖 ReentrantLock
- 互斥同步面臨的主要問題是進行執行緒阻塞和喚醒所帶來的性能開銷,因此這種同步也被稱為阻塞同步。【種悲觀的並發策略】
- 高並發場景,建議使用Lock鎖,Lock鎖要比使用Synchronize關鍵字在性能上有極大的提高,而且
Lock鎖底層就是通過AQS+CAS機制實現的
,而CAS 也是解決執行緒安全的另外一種方式。
★ 說說lock 和 synchronized 鎖的區別
synchronized 是一個
關鍵字
,使用C++實現的,沒辦法控制鎖的開始、鎖結束,也沒辦法中斷執行緒的執行而 lock 是
java層面的實現
,可以獲取鎖的狀態,開啟鎖,釋放鎖,通過設置可以中斷執行緒的執行,更加靈活是否自動是否鎖:synchronized 會自動是否鎖,而 lock 需要手動調用unlock 方法釋放,否則會死循環
lock.lock();//其他沒有拿到鎖的執行緒?阻塞 卡著不動 boolean res = lock.tryLock(1000, TimeUnit.MILLISECONDS);//一秒之後如果沒有拿到鎖,就返回false lock.lockInterruptibly();//中斷方法
(2) 樂觀並發策略
-
CAS 樂觀並發策略,無鎖機制
-
像執行緒安全的 原子操作類Atomic 底層就是使用 CAS 思想 ,只是落地實現是依賴 Unsafe 的CPU 原語級別的彙編操作
new AtomicInteger().getAndAdd(1);//獲取到當前值並加1 // 底層實現 public final int getAndAdd(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta); } public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
工作中,不建議使用Unsafe 類,類名就提示你了”不安全”!
- 基於衝突檢測的樂觀並發策略,通俗地說就是不管風險,先進行操作,如果沒有其他執行緒爭用共享數據,那操作就直接成功了;如果共享的數據的確被爭用,產生了衝突,那再進行其他的補償措施,最常用的補償措施是不斷地重試,直到出現 沒有競爭的共享數據為止。
- 使用樂觀並發策略需要「硬體指令集的發展」?因為我們必須要求
操作和衝突檢測這兩個步驟具備原子性
。靠什麼來保證原子性?==>cpu 指令
-
CAS 可能出現的問題:死循環、 ABA 問題
- ABA 問題的解決:帶有 標記的
原子引用類 AtomicStampedReference
==> 類似思想”樂觀鎖,加版本號”
- ABA 問題的解決:帶有 標記的
(3) 執行緒私有局部變數
- 執行緒本地存儲,比如 threadLocal,執行緒私有的局部變數,避免的共享變數的競爭
(4) 其他方式
-
使用 volatile
,利用它的可見性,禁止指令重排的特性,但原子性沒法保證。在多執行緒下沒有嚴格的寫操作衝突同步要求,推薦使用。常用的場景是:使用volatile變數控制執行緒的終止。
-
寫是複製–CopyOnWriteArrayList
CopyOnWriteArrayList是JUC包提供的執行緒安全的List。
3、總結常用的解決執行緒安全方式
- 加鎖:sync、lock
- (無鎖)樂觀並發:CAS
- 原子操作類:atomic
- (執行緒局部變數)變數不共享:threadlocal
- volatile
如果本文對你有幫助的話記得給一樂點個贊哦,感謝!