您好,登錄后才能下訂單哦!
這篇文章主要講解了“Java中synchronized的作用及用法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java中synchronized的作用及用法”吧!
synchronized是屬于JVM層面的一個關鍵字,底層是通過一個monitor對象(管程對象)來完成,由于wait()/notify()等方法也依賴于monitor對象,所以只有在同步的塊或者方法中才能調用wait/notify等方法
synchronized同步語句塊的實現使用monitorenter和 monitorexit 指令。
monitorenter:指令指向同步代碼塊的開始位置
monitorexit:指令則指明同步代碼塊的結束位置
當執行monitorenter指令時,當前線程將試圖獲取 objectref(即對象鎖) 所對應的 monitor的持有權,當 objectref的monitor 的進入計數器**為0,那線程可以成功取得 monitor,并將計數器值設置為 1,取鎖成功。
如果當前線程已經擁有 objectref 的 monitor 的持有權,那它可以重入這個 monitor (關于重入性稍后會分析),重入時計數器的值也會加 1。
倘若其他線程已經擁有objectref 的 monitor 的所有權,那當前線程將被阻塞,直到正在執行線程執行完畢,即monitorexit指令被執行,執行線程將釋放monitor(鎖)并設置計數器值為0,其他線程將有機會持有 monitor ;**
為了保證在方法異常完成時 monitorenter 和 monitorexit 指令依然可以正確配對執行,編譯器會自動產生一個異常處理器,這個異常處理器聲明可處理所有的異常,它的目的就是用來執行 monitorexit 指令。
從字節碼中也可以看出多了一個monitorexit指令,它就是異常結束時被執行的釋放monitor的指令;
每個對象有一個管程對象(monitor),當monitor被占用時就會處于鎖定狀態;線程執行monitorenter指令時嘗試獲取monitor的所有權,過程如下:
如果monitor的進入計數器為0,則該線程進入monitor,然后將進入計數器設置為1,該線程即為monitor的所有者;
如果線程已經之前占用了該monitor,本次只是重新進入,則將monitor的進入計數器加1;
如果其他線程已經占用了monitor,則該線程進入阻塞狀態,直到monitor的進入計數器為0,再重新嘗試獲取monitor的所有權;
執行monitorexit的線程必須是objectref(即對象鎖)所對應的monitor的所有者;
指令執行時,monitor的進入計數器減1,如果減1后進入計數器為0,那線程退出monitor,不再是這個monitor的所有者。其他被這個monitor阻塞的線程可以嘗試去獲取這個 monitor 的所有權.
方法級的同步是隱式,即無需通過字節碼指令(monitorenter和monitorexit)來控制的。 它實現在方法調用和返回操作之中。
JVM可以從方法常量池中的方法表結構(method_info Structure) 中的ACC_SYNCHRONIZED訪問標志區分一個方法是否同步方法。
當方法調用時,調用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標志是否被設置,如果設置了,執行線程將先持有monitor(虛擬機規范中用的是管程一詞)。
然后再執行方法,最后在方法完成(無論是正常完成還是非正常完成)時釋放monitor。
在方法執行期間,執行線程持有了monitor,其他任何線程都無法再獲得同一個monitor。如果一個同步方法執行期間拋出了異常,并且在方法內部無法處理此異常,那這個同步方法所持有的monitor將在異常拋到同步方法之外時自動釋放。
感謝各位的閱讀,以上就是“Java中synchronized的作用及用法”的內容了,經過本文的學習后,相信大家對Java中synchronized的作用及用法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。