自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Synchronized關(guān)鍵字的底層原理?

開發(fā) 前端
在 Java 中,關(guān)鍵字 synchronized 可以保證在同一個時刻,只有一個線程可以執(zhí)行某個方法或者某個代碼塊(主要是對方法或者代碼塊中存在共享數(shù)據(jù)的操作),同時我們還應(yīng)該注意到 synchronized 的另外一個重要的作用,synchronized 可保證一個線程的變化(主要是共享數(shù)據(jù)的變化)被其他線程所看到。

1. synchronized的基本使用

在現(xiàn)實場景中,搶票代碼,如果不加鎖,就會出現(xiàn)超賣或者一張票賣給多個人

Synchronized對象鎖采用互斥的方式讓同一時刻至多只有一個線程能持有對象鎖,其它線程再想獲取這個對象鎖時就會阻塞住,代碼如下

public class synchronizedTest {
    // 創(chuàng)建一個靜態(tài)對象作為鎖
    static Object lock = new Object();
    // 初始票數(shù)
    int ticketNum = 20;

    // 獲取票的方法,使用 synchronized 修飾確保線程安全
    public synchronized void getTicket() {
        // 使用當前對象作為鎖
        synchronized (this) {
            // 如果票數(shù)已經(jīng)為零,則返回
            if (ticketNum <= 0) {
                return;
            }
            System.out.println(Thread.currentThread().getName() + "搶到一張票,剩余:" + ticketNum);
            // 非原子性操作,扣除一張票
            ticketNum--;
        }
    }

    public static void main(String[] args) {
        // 創(chuàng)建 synchronizedTest 實例
        synchronizedTest synchronizedTest = new synchronizedTest();
        // 創(chuàng)建并啟動 20 個線程
        for (int i = 0; i < 20; i++) {
            // 調(diào)用獲取票的方法
            new Thread(() -> synchronizedTest.getTicket()).start();
        }
    }
}

通過以上代碼,加synchronized鎖,就可以防止超賣

特別說明:synchronized 關(guān)鍵字的底層實現(xiàn)涉及到 Java 虛擬機中的監(jiān)視器(Monitor)機制。每個 Java 對象都與一個 Monitor 相關(guān)聯(lián),Monitor 負責對象的鎖定和解鎖,以及線程的阻塞和喚醒。

2. Monitor

Monitor 被翻譯為監(jiān)視器,是由jvm提供,c++語言實現(xiàn)

使用一下簡單代碼中查看monitor,通過javap命令查看clsss的字節(jié)碼

public class MonitorTest {
    static final Object lock = new Object();
    static int counter = 0;
    public static void main(String[] args) {
        synchronized (lock) {
            counter++;
        }
    }
}

圖片圖片

  • monitorenter: 上鎖開始的地方
  • monitorexit:  解鎖的地方
  • 其中被monitorenter和monitorexit包圍住的指令就是上鎖的代碼

思考:為什么會出現(xiàn)兩個monitorexit

有兩個monitorexit的原因,第二個monitorexit是為了防止鎖住的代碼拋異常后不能及時釋放鎖在使用了synchornized代碼塊時需要指定一個對象,所以synchornized也被稱為對象鎖

monitor主要就是跟這個對象產(chǎn)生關(guān)聯(lián),如下圖

圖片圖片

Monitor內(nèi)部具體的存儲結(jié)構(gòu):

  • Owner:存儲當前獲取鎖的線程的,只能有一個線程可以獲取
  • EntryList:關(guān)聯(lián)沒有搶到鎖的線程,處于Blocked狀態(tài)的線程
  • WaitSet:關(guān)聯(lián)調(diào)用了wait方法的線程,處于Waiting狀態(tài)的線程

具體的流程:

  • 代碼進入synchorized代碼塊,先讓lock(對象鎖)關(guān)聯(lián)的monitor,然后判斷Owner是否有線程持有
  • 如果沒有線程持有,則讓當前線程持有,表示該線程獲取鎖成功
  • 如果有線程持有,則讓當前線程進入entryList進行阻塞,如果Owner持有的線程已經(jīng)釋放了鎖,在EntryList中的線程去競爭鎖的持有權(quán)(非公平)
  • 如果代碼塊中調(diào)用了wait()方法,則會進去WaitSet中進行等待

3.面試題

面試官:synchronized關(guān)鍵字的底層原理?

  • Synchronized【對象鎖】
  • 采用互斥的方式讓同一時刻至多只有一個線程能持有【對象鎖】
  • 它的底層由monitor實現(xiàn)的,monitor是jvm級別的對象( C++實現(xiàn)),線程獲得鎖需要使用對象(鎖)關(guān)聯(lián)monitor
  • 在monitor內(nèi)部有三個屬性,分別是owner、entrylist、waitset
  • 其中owner是關(guān)聯(lián)的獲得鎖的線程,并且只能關(guān)聯(lián)一個線程;entrylist關(guān)聯(lián)的是處于阻塞狀態(tài)的線程;waitset關(guān)聯(lián)的是處于Waiting狀態(tài)的線程
責任編輯:武曉燕 來源: springboot葵花寶典
相關(guān)推薦

2019-12-20 15:19:41

Synchroinze線程安全

2024-11-20 15:55:57

線程Java開發(fā)

2022-01-26 00:03:00

關(guān)鍵字線程JVM

2021-03-10 15:59:39

JavaSynchronize并發(fā)編程

2021-01-12 09:22:18

Synchronize線程開發(fā)技術(shù)

2009-08-12 13:37:01

Java synchr

2017-05-27 20:59:30

Java多線程synchronize

2021-08-15 08:11:54

AndroidSynchronize關(guān)鍵字

2021-01-08 08:34:09

Synchronize線程開發(fā)技術(shù)

2009-06-29 18:26:11

Java多線程Synchronize同步類

2022-12-26 09:27:48

Java底層monitor

2011-03-09 14:36:44

synchronizevolatile

2023-05-15 09:39:10

Java監(jiān)視器鎖

2022-05-06 08:32:40

Pythonwith代碼

2022-02-17 08:31:38

C語言staic關(guān)鍵字

2021-02-01 13:10:07

Staticc語言UNIX系統(tǒng)

2025-01-09 10:30:40

2022-11-12 18:32:50

Golangomitemptyjson

2009-09-02 09:24:03

C# this關(guān)鍵字

2009-09-17 09:30:00

Linq LET關(guān)鍵字
點贊
收藏

51CTO技術(shù)棧公眾號