线程中的各种锁
死鎖
是指兩個或兩個以上的線程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產生了死鎖,這些永遠在互相等待的線程稱為死鎖進程。 由于資源占用是互斥的,當某個線程提出申請資源后,使得有關線程在無外力協(xié)助下,永遠分配不到必需的資源而無法繼續(xù)運行,這就產生了一種特殊現象:死鎖。
死鎖產生的四個條件
- 互斥條件:一個資源每次只能被一個線程使用。
- 請求與保持條件:一個線程因請求資源而阻塞時,對已獲得的資源保持不放。
- 不剝奪條件:線程已獲得的資源,在末使用完之前,不能強行剝奪。
- 循環(huán)等待條件:若干線程之間形成一種頭尾相接的循環(huán)等待資源關系。
如何避免死鎖 - 從死鎖的四個必要條件來看,破壞其中的任意一個條件就可以避免死鎖。但互斥條件是由資源本身決定的,不剝奪條件一般無法破壞,要實現的話得自己寫更多的邏輯。
- 避免無限期的等待:用Lock.tryLock(),wait/notify等方法寫出請求一定時間后,放棄已經擁有的鎖的程序。
- 注意鎖的順序:以固定的順序獲取鎖,可以避免死鎖。
- 開放調用:即只對有請求的進行封鎖。你應當只想你要運行的資源獲取封鎖,比如在上述程序中我在封鎖的完全的對象資源。但是如果我們只對它所屬領域中的一個感興趣,那我們應當封鎖住那個特殊的領域而并非完全的對象。
- 最后,如果能避免使用多個鎖,甚至寫出無鎖的線程安全程序是再好不過了。
- 避免多次鎖定。盡量避免同一個線程對多個 Lock 進行鎖定。例如上面的死鎖程序,主線程要對 A、B 兩個對象的 Lock 進行鎖定,副線程也要對 A、B 兩個對象的 Lock 進行鎖定,這就埋下了導致死鎖的隱患。
樂觀鎖
就像它的名字一樣,對于并發(fā)間操作產生的線程安全問題持樂觀狀態(tài),樂觀鎖認為競爭不總是會發(fā)生,因此它不需要持有鎖,將比較-替換這兩個動作作為一個原子操作嘗試去修改內存中的變量,如果失敗則表示發(fā)生沖突,那么就應該有相應的重試邏輯。
優(yōu)點和缺點
樂觀并發(fā)控制相信事務之間的數據競爭(data race)的概率是比較小的,因此盡可能直接做下去,直到提交的時候才去鎖定,所以不會產生任何鎖和死鎖。但如果直接簡單這么做,還是有可能會遇到不可預 期的結果,例如兩個事務都讀取了數據庫的某一行,經過修改以后寫回數據庫,這時就遇到了問題。
悲觀鎖
還是像它的名字一樣,對于并發(fā)間操作產生的線程安全問題持悲觀狀態(tài),悲觀鎖認為競爭總是會發(fā)生,因此每次對某資源進行操作時,都會持有一個獨占的鎖,就像synchronized,不管三七二十一,直接上了鎖就操作資源了。
優(yōu)點和缺點
悲觀并發(fā)控制實際上是”先取鎖再訪問”的保守策略,為數據處理的安全提供了保證。但是在效率方面,處理加鎖的機制會讓數據庫產生額外的開銷,還有增 加產生死鎖的機會;另外,在只讀型事務處理中由于不會產生沖突,也沒必要使用鎖,這樣做只能增加系統(tǒng)負載;還有會降低了并行性,一個事務如果鎖定了某行數 據,其他事務就必須等待該事務處理完才可以處理那行數
共享鎖
共享鎖指的就是對于多個不同的事務,對同一個資源共享同一個鎖。相當于對于同一把門,它擁有多個鑰匙一樣。
排它鎖
排它鎖與共享鎖相對應,就是指對于多個不同的事務,對同一個資源只能有一把鎖。與共享鎖類型,在需要執(zhí)行的語句后面加上for update就可以了
行鎖
行鎖,由字面意思理解,就是給某一行加上鎖,也就是一條記錄加上鎖。
比如之前演示的共享鎖語句
SELECT * from city where id = “1” lock in share mode;
由于對于city表中,id字段為主鍵,就也相當于索引。執(zhí)行加鎖時,會將id這個索引為1的記錄加上鎖,那么這個鎖就是行鎖。
表鎖
表鎖,和行鎖相對應,給這個表加上鎖。
總結
- 上一篇: Springboot中实现文件上传功能
- 下一篇: java中的异常种类和区别以及处理机制和