Spring如何更好地解決線程安全問題?
線程安全問題概述賣票問題分析單窗口賣票
一個窗口(單線程)賣100張票沒有問題單線程程序是不會出現線程安全問題的多個窗口賣不同的票3個窗口一起賣票,賣的票不同,也不會出現問題多線程程序,沒有訪問共享數據,不會產生問題多個窗口賣相同的票3個窗口賣的票是一樣的,就會出現安全問題多線程訪問了共享的數據,會產生線程安全問題線程安全問題代碼實現模擬賣票案例創建3個線程,同時開啟,對共享的票進行出售線程安全問題原理分析分析:線程安全問題正常是不允許產生的,我們可以讓一個線程在訪問共享數據的時候,無論是否失去了cpu的執行權;讓其他的線程只能等待,等待當前線程賣完票,其他線程在進行賣票。解決線程安全問題辦法1-synchronized同步代碼塊同步代碼塊:synchronized 關鍵字可以用于方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。使用synchronized同步代碼塊格式:synchronized(鎖對象){可能會出現線程安全問題的代碼(訪問了共享數據的代碼)}代碼實現如下:注意:代碼塊中的鎖對象,可以使用任意的對象。但是必須保證多個線程使用的鎖對象是同一個。鎖對象作用:把同步代碼塊鎖住,只讓一個線程在同步代碼塊中執行。同步技術原理分析同步技術原理:使用了一個鎖對象,這個鎖對象叫同步鎖,也叫對象鎖,也叫對象監視器3個線程一起搶奪cpu的執行權,誰搶到了誰執行run方法進行賣票。t0搶到了cpu的執行權,執行run方法,遇到synchronized代碼塊這時t0會檢查synchronized代碼塊是否有鎖對象發現有,就會獲取到鎖對象,進入到同步中執行t1搶到了cpu的執行權,執行run方法,遇到synchronized代碼塊這時t1會檢查synchronized代碼塊是否有鎖對象發現沒有,t1就會進入到阻塞狀態,會一直等待t0線程歸還鎖對象,t0線程執行完同步中的代碼,會把鎖對象歸 還給同步代碼塊t1才能獲取到鎖對象進入到同步中執行總結:同步中的線程,沒有執行完畢不會釋放鎖,同步外的線程沒有鎖進不去同步。解決線程安全問題辦法2-synchronized普通同步方法同步方法:使用synchronized修飾的方法,就叫做同步方法,保證A線程執行該方法的時候,其他線程只能在方法外等著。格式:public synchronized void payTicket(){可能會出現線程安全問題的代碼(訪問了共享數據的代碼)}代碼實現:分析:定義一個同步方法,同步方法也會把方法內部的代碼鎖住,只讓一個線程執行。同步方法的鎖對象是誰?就是實現類對象 new RunnableImpl(),也是就是this,所以同步方法是鎖定的this對象。解決線程安全問題辦法3-synchronized靜態同步方法同步方法:使用synchronized修飾的方法,就叫做同步方法,保證A線程執行該方法的時候,其他線程只能在方法外等著。對于static方法,我們使用當前方法所在類的字節碼對象(類名.class)。格式:public static synchronized void payTicket(){可能會出現線程安全問題的代碼(訪問了共享數據的代碼)}代碼實現:分析:靜態的同步方法鎖對象是誰?不能是this,this是創建對象之后產生的,靜態方法優先于對象靜態方法的鎖對象是本類的class屬性–>class文件對象(反射)。解決線程安全問題辦法4-Lock鎖Lock接口中的方法:public void lock() :加同步鎖。public void unlock() :釋放同步鎖使用步驟:在成員位置創建一個ReentrantLock對象在可能會出現安全問題的代碼前調用Lock接口中的方法lock獲取鎖在可能會出現安全問題的代碼后調用Lock接口中的方法unlock釋放鎖代碼實現:分析:java.util.concurrent.locks.Lock接口Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。相比Synchronized,ReentrantLock類提供了一些高級功能,主要有以下3項:等待可中斷,持有鎖的線程長期不釋放的時候,正在等待的線程可以選擇放棄等待,這相當于Synchronized來說可以避免出現死鎖的情況。通過lock.lockInterruptibly()來實現這個機制。公平鎖,多個線程等待同一個鎖時,必須按照申請鎖的時間順序獲得鎖,Synchronized鎖非公平鎖,ReentrantLock默認的構造函數是創建的非公平鎖,可以通過參數true設為公平鎖,但公平鎖表現的性能不是很好。公平鎖、非公平鎖的創建方式:鎖綁定多個條件,一個ReentrantLock對象可以同時綁定多個對象。ReenTrantLock提供了一個Condition(條件)類,用來實現分組喚醒需要喚醒的線程們,而不是像synchronized要么隨機喚醒一個線程要么喚醒全部線程。ReentrantLock和Synchronized的區別相同點:它們都是加鎖方式同步;都是重入鎖;阻塞式的同步;也就是說當如果一個線程獲得了對象鎖,進入了同步塊,其他訪問該同步塊的線程都必須阻塞在同步塊外面等待,而進行線程阻塞和喚醒的代價是比較高的(操作系統需要在用戶態與內核態之間來回切換,代價很高,不過可以通過對鎖優化進行改善);上一篇火箭彈能夠被攔截嗎
下一篇你有哪些特殊的癖好呢