關於 java鎖,mysql鎖,以及樂觀鎖、悲觀鎖、死鎖的總結


以下都是用自己的語言的自我理解與總結,僅供參考

 

首先,要明白為什么會有鎖,簡單點就是,多個進程(或者多個線程)需要同時修改同一個資源的時候,為了保證順序修改而加的鎖,如果不順序修改,那就會錯亂。

1、線程和進程的區別

進程:系統資源分配的最小單位,指運行中的應用程序。

線程:系統分配處理器時間資源的基本單元,運行在進程中的一個單元執行流,一個進程可以有多個線程。

一個進程中的多個線程之間內存數據是共享的,共享的數據修改需要加鎖,在java中就可以用synchronized或者reentrantlock實現

多個進程之間的內存是獨立的,不共享的,多個進程之間的通信常用的有管道(如linux中的“|”),socket請求(如http請求數據)

 

2、java中的鎖

主要有synchronized 和 reentrantlock 2種方法實現

reentrantlock支持鎖等待,鎖返回(即tryLock()如果加鎖不成功返回false,成功返回true),鎖等待超時返回(tryLock(time),等待time后還獲取不到鎖就返回false)

synchronized只支持鎖等待

相比reentrantlock適用的場景更多

 

3、樂觀鎖、悲觀鎖、死鎖

  a、樂觀鎖:查詢數據的時候不加鎖,修改數據的時候檢查數據是否有沖突,如果有沖突,就返回錯誤,讓用戶重試或者其他操作,一般通過加版本號,或者時間戳實現,實際並沒有加鎖的操作,不會發生死鎖

  b、悲觀鎖:在查詢數據的時候就加鎖,然后再執行真正的修改數據操作,修改完成,再釋放鎖。優點是安全,缺點是,減少了系統的並行性。主要由數據庫自主實現悲觀鎖,比如mysql的 select ... for update

  c、死鎖:四個必要條件,1、互斥,2、不可剝奪,3、請求與保持,4、循環等待,由於悲觀鎖用到了鎖,實際只有悲觀鎖時才會發生死鎖,避免死鎖,就是打破四個條件之一,簡單的可以打破第四個條件,不讓循環等待,設置超時機制,如果等待固定時間還獲取不到鎖,就拋出錯誤,釋放自己的鎖

  d、mysql模擬死鎖,

  比如2個事務,事務A、事務B,都查詢id=1和id=2的數據,並加鎖

  事務A,select * from t where id=1 for update,對id=1數據加鎖

  然后,事務B,select * from t where id=2 for update,對id=2數據加鎖

  事務A,此時又需要查詢id=2的數據,於是select * from t where id=2 for update,因為事務B已經加過id=2的鎖了,所以事務A就會一直等待

       事務B,此時又需要查詢id=1的數據,於是select * from t where id=1 for update,因為事務A已經加過id=1的鎖了,所以事務B也會一直等待

  此時就發生了死鎖,會等待系統設置的超時時間,mysql會檢查這種死鎖,超過超時時間(mysql設置innodb_lock_wait_timeout),然后報錯回滾,才打破死鎖

 

4、mysql中的鎖

       mysql innodb 模式中有表級索、行級鎖

  行級鎖又有排他鎖、共享鎖,查詢加排他鎖就是select ... for update這種,正常的update delet insert語句會自動加上排他鎖

  共享鎖,在查詢中加上lock in share mode就表示共享鎖,適用於兩張表存在業務關系時的一致性要求,for  update適用於操作同一張表時的一致性要求,參考大佬博客,https://blog.csdn.net/cug_jiang126com/article/details/50544728

  表級索,mysql5.7之前的ddl操作會鎖表,比如加字段,加索引,之后不會,還有ddl中,如果update 是全表的數據也會鎖表

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM