在現實場景中,搶票代碼,如果不加鎖,就會出現超賣或者一張票賣給多個人
Synchronized對象鎖采用互斥的方式讓同一時刻至多只有一個線程能持有對象鎖,其它線程再想獲取這個對象鎖時就會阻塞住,代碼如下
public class synchronizedTest { // 創建一個靜態對象作為鎖 static Object lock = new Object(); // 初始票數 int ticketNum = 20; // 獲取票的方法,使用 synchronized 修飾確保線程安全 public synchronized void getTicket() { // 使用當前對象作為鎖 synchronized (this) { // 如果票數已經為零,則返回 if (ticketNum <= 0) { return; } System.out.println(Thread.currentThread().getName() + "搶到一張票,剩余:" + ticketNum); // 非原子性操作,扣除一張票 ticketNum--; } } public static void main(String[] args) { // 創建 synchronizedTest 實例 synchronizedTest synchronizedTest = new synchronizedTest(); // 創建并啟動 20 個線程 for (int i = 0; i < 20; i++) { // 調用獲取票的方法 new Thread(() -> synchronizedTest.getTicket()).start(); } }}
通過以上代碼,加synchronized鎖,就可以防止超賣
特別說明:synchronized 關鍵字的底層實現涉及到 Java 虛擬機中的監視器(Monitor)機制。每個 Java 對象都與一個 Monitor 相關聯,Monitor 負責對象的鎖定和解鎖,以及線程的阻塞和喚醒。
Monitor 被翻譯為監視器,是由jvm提供,c++語言實現
使用一下簡單代碼中查看monitor,通過javap命令查看clsss的字節碼
public class MonitorTest { static final Object lock = new Object(); static int counter = 0; public static void main(String[] args) { synchronized (lock) { counter++; } }}
圖片
思考:為什么會出現兩個monitorexit
有兩個monitorexit的原因,第二個monitorexit是為了防止鎖住的代碼拋異常后不能及時釋放鎖在使用了synchornized代碼塊時需要指定一個對象,所以synchornized也被稱為對象鎖
monitor主要就是跟這個對象產生關聯,如下圖
圖片
Monitor內部具體的存儲結構:
具體的流程:
面試官:synchronized關鍵字的底層原理?
- Synchronized【對象鎖】
- 采用互斥的方式讓同一時刻至多只有一個線程能持有【對象鎖】
- 它的底層由monitor實現的,monitor是jvm級別的對象( C++實現),線程獲得鎖需要使用對象(鎖)關聯monitor
- 在monitor內部有三個屬性,分別是owner、entrylist、waitset
- 其中owner是關聯的獲得鎖的線程,并且只能關聯一個線程;entrylist關聯的是處于阻塞狀態的線程;waitset關聯的是處于Waiting狀態的線程
本文鏈接:http://www.www897cc.com/showinfo-26-76499-0.htmlSynchronized關鍵字的底層原理?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 記一次 .NET某設備監控自動化系統 CPU爆高分析
下一篇: 深入理解Java淺拷貝與深拷貝