多執行緒的安全問題及解決方案
概念
當多個執行緒同時共享同一個全域性變數做寫的操作的時候,可能會受到其他執行緒的干擾,就會產生執行緒安全問題,出現資料髒讀
解決方案
核心思想:同一個時刻保證只允許單執行緒執行
方案
- 使用java鎖的機制Synchronized、Lock鎖和CAS無鎖機制
- 對於程式碼中如果在多執行緒同時執行操作的情況下,可能會受到其他執行緒的干擾的程式碼採用鎖的機制,在同一個時刻只能保證只有一個執行緒去執行,只有獲取到鎖之後,才能夠進入該程式碼塊執行,程式碼執行完之後釋放鎖之後其他執行緒去獲取鎖才可以執行。
- 沒有獲取到鎖的執行緒,則一直會排隊阻塞,整個過程是一個悲觀狀態
Synchronized的基本用法
可以定義任意物件作為鎖,但是需要注意:如果該方法為普通方法的情況下,可以使用普通物件或者屬性作為鎖
如果該方法為靜態方法的情況,則必須使用當前類的Class或者是靜態屬性作為鎖
例項方法
如果在普通方法上加上鎖,則預設表示使用this鎖
靜態程式碼塊
如果是在靜態方法上加上鎖,則預設表示使用當前類的.class鎖。
鎖的重入鎖
package com.mayikt;
public class Thread006 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ",我是子執行緒");
a();
}
public synchronized void a() {
System.out.println(Thread.currentThread().getName() + ",我是方法A");
//呼叫b方法獲取鎖的時候可以之間獲取this物件了
b();
}
public synchronized void b() {
System.out.println(Thread.currentThread().getName() + ",我是方法B");
}
}
多執行緒死鎖產生的原因
在同步中巢狀同步,你中有我,我中有你,會出現死鎖的現象
Lock鎖的基本用法
在使用阻塞等待獲取鎖的方式中,必須在try程式碼塊之外,並且加鎖方法和try程式碼塊之間沒有任何可能丟擲異常的方法呼叫,避免加鎖成功後,在finally無法解鎖
說明一:如果在lock方法與try程式碼塊之間的方法呼叫丟擲異常,那麼無法解鎖,造成其他執行緒無法成功獲取鎖
說明二:如果lock方法在try程式碼塊之內,可能由於丟擲異常,導致在finally程式碼塊中,unlock對未加鎖的物件解鎖,它會呼叫tryRelease,丟擲IlegalMonitorStateException異常
說明三:在Lock物件的lock方法實現中可能丟擲uncheck異常
lock加鎖的程式碼
private void ticket() {
if (count > 0) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "正在出第" + (101 - count) + "張票");
count--;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
讀寫鎖ReadAndWriteLock
程式碼例子
。
package com.mayikt;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyTask {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 讀讀共享
*/
public void read() {
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + ",正在開始讀取");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + ",正在結束讀取");
} catch (Exception e) {
}
lock.readLock().unlock();
}
/**
* 寫寫互斥
*/
public void write() {
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + ",正在開始寫入");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + ",正在結束寫入");
} catch (Exception e) {
}
lock.writeLock().unlock();
}
public static void main(String[] args) {
MyTask myTask = new MyTask();
/* for (int i = 0; i < 10; i++) {
new Thread(() -> {
myTask.write();
}).start();
}*/
for (int i =0; i <10;i++){
new Thread(() -> {
myTask.read();
}).start();
new Thread(() -> {
myTask.write();
}).start();
}
}
}
Lock與Synchronized鎖的區別
- Synchronized屬於java內建的關鍵字,而lock鎖是基於aqs封裝的一個鎖的框架
- Synchronized當程式碼執行結束自動釋放鎖,而lock需要人工釋放鎖,相對於lock鎖更加靈活
參考:螞蟻課堂
相關文章
- 多執行緒併發同步問題及解決方案執行緒
- Python執行緒安全問題及解決方法Python執行緒
- iOS多執行緒全套:執行緒生命週期,多執行緒的四種解決方案,執行緒安全問題,GCD的使用,NSOperation的使用iOS執行緒GC
- Java中解決多執行緒資料安全問題Java執行緒
- Java多執行緒:資料一致性問題及解決方案Java執行緒
- 多執行緒併發安全問題詳解執行緒
- 多執行緒,你覺得你安全了?(執行緒安全問題)執行緒
- Java多執行緒中執行緒安全與鎖問題Java執行緒
- 多執行緒問題解釋執行緒
- 多執行緒的安全性問題(三)執行緒
- 多執行緒併發執行及解決方法執行緒
- Spring中多執行緒的使用及問題Spring執行緒
- Python | 多執行緒死鎖問題的巧妙解決方法Python執行緒
- 5分鐘搞懂多執行緒安全問題執行緒
- 小度分享-【多執行緒工作及執行緒安全】執行緒
- ArrayList 的執行緒安全問題執行緒
- 如何解決多執行緒併發問題執行緒
- 03 執行緒安全問題執行緒
- SimpleDateFormat 執行緒安全問題ORM執行緒
- java多執行緒程式設計問題以及解決辦法Java執行緒程式設計
- parallelStream中的執行緒安全問題Parallel執行緒
- 【Java多執行緒】執行緒安全的集合Java執行緒
- Java學習(28)—(執行緒的控制/生命週期/解決安全問題)Java執行緒
- 多執行緒相關問題執行緒
- 深入JAVA執行緒安全問題Java執行緒
- 企圖使用c++執行緒解決nodejs單執行緒問題C++執行緒NodeJS
- 多執行緒環境下 PyQtGraph 繪畫解決方案執行緒QT
- 解決POI多執行緒匯出時資料錯亂問題執行緒
- 多執行緒中自定義執行緒池與shiro導致的許可權錯亂問題解決執行緒
- 多執行緒系列之 執行緒安全執行緒
- iOS 多執行緒之執行緒安全iOS執行緒
- WebMagic多執行緒導致註解失效問題Web執行緒
- 多執行緒引起的效能問題分析執行緒
- 深入解讀HashMap執行緒安全性問題HashMap執行緒
- 模板方法中的執行緒安全問題執行緒
- lambda中stream執行緒安全的問題執行緒
- Java 執行緒安全問題的本質Java執行緒
- 用 UI 多執行緒處理 WPF 大量渲染的解決方案UI執行緒