線程安全問題概述
賣票問題分析
- 單窗口賣票
- 多個窗口賣不同的票
3個窗口一起賣票,賣的票不同,也不會出現問題
- 多個窗口賣相同的票
3個窗口賣的票是一樣的,就會出現安全問題
線程安全問題代碼實現
線程安全問題原理分析
解決線程安全問題辦法1-synchronized同步代碼塊
synchronized(鎖對象){
可能會出現線程安全問題的代碼(訪問了共享數據的代碼)
}
- 代碼塊中的鎖對象,可以使用任意的對象。
- 但是必須保證多個線程使用的鎖對象是同一個。
- 鎖對象作用:把同步代碼塊鎖住,只讓一個線程在同步代碼塊中執行。
同步技術原理分析
- t0搶到了cpu的執行權,執行run方法,遇到synchronized代碼塊這時t0會檢查synchronized代碼塊是否有鎖對象
- t1搶到了cpu的執行權,執行run方法,遇到synchronized代碼塊這時t1會檢查synchronized代碼塊是否有鎖對象
解決線程安全問題辦法2-synchronized普通同步方法
publicsynchronizedvoidpayTicket(){
可能會出現線程安全問題的代碼(訪問了共享數據的代碼)
}
解決線程安全問題辦法3-synchronized靜態同步方法
publicstaticsynchronizedvoidpayTicket(){
可能會出現線程安全問題的代碼(訪問了共享數據的代碼)
}
解決線程安全問題辦法4-Lock鎖
- publicvoidlock():加同步鎖。
- publicvoidunlock():釋放同步鎖
- 在成員位置創建一個ReentrantLock對象
- 在可能會出現安全問題的代碼前調用Lock接口中的方法lock獲取鎖
- 在可能會出現安全問題的代碼后調用Lock接口中的方法unlock釋放鎖
java.util.concurrent.locks.Lock接口
- 等待可中斷,持有鎖的線程長期不釋放的時候,正在等待的線程可以選擇放棄等待,這相當于Synchronized來說可以避免出現死鎖的情況。通過lock.lockInterruptibly()來實現這個機制。
- 公平鎖,多個線程等待同一個鎖時,必須按照申請鎖的時間順序獲得鎖,Synchronized鎖非公平鎖,ReentrantLock默認的構造函數是創建的非公平鎖,可以通過參數true設為公平鎖,但公平鎖表現的性能不是很好。
- 鎖綁定多個條件,一個ReentrantLock對象可以同時綁定多個對象。ReenTrantLock提供了一個Condition(條件)類,用來實現分組喚醒需要喚醒的線程們,而不是像synchronized要么隨機喚醒一個線程要么喚醒全部線程。
ReentrantLock和Synchronized的區別
- 它們都是加鎖方式同步;
- 都是重入鎖;
- 阻塞式的同步;也就是說當如果一個線程獲得了對象鎖,進入了同步塊,其他訪問該同步塊的線程都必須阻塞在同步塊外面等待,而進行線程阻塞和喚醒的代價是比較高的(操作系統需要在用戶態與內核態之間來回切換,代價很高,不過可以通過對鎖優化進行改善);