執行緒安全問題的產生條件、解決方式
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
如果本文對你有幫助的話記得給一樂點個贊哦,感謝!
「其他文章」
- 執行緒池底層原理詳解與原始碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裡都有
- 【前端必會】webpack loader 到底是什麼
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8原始碼解讀
- 詳解JS中 call 方法的實現
- 列印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang程式碼
- Springboot之 Mybatis 多資料來源實現
- CAS核心思想、底層實現
- 面試突擊86:SpringBoot 事務不回滾?怎麼解決?
- 基於electron vue element構建專案模板之【打包篇】
- MiniWord .NET Word模板引擎,藉由Word模板和資料簡單、快速生成檔案。
- 認識執行緒,初始併發
- 1-VSCode搭建GD32開發環境
- 初識設計模式 - 原型模式
- 執行緒安全問題的產生條件、解決方式
- 2>&1到底是什麼意思?