最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

synchronized底層原理之JVM層面的鎖實現(xiàn)細節(jié)與流程

 更新時間:2026年01月04日 09:22:53   作者:C雨后彩虹  
本文從JVM底層視角,詳細拆解了synchronized的實現(xiàn)邏輯,涵蓋鎖的存儲載體(對象頭的MarkWord)、鎖的觸發(fā)指令(monitorenter/monitorexit指令和ACC_SYNCHRONIZED標(biāo)志位)以及鎖的調(diào)度機制,感興趣的朋友跟隨小編一起看看吧

一、前言

在上一篇文章中,我們掌握了其基礎(chǔ)用法、核心特性及適用場景,知道它能解決并發(fā)編程的原子性、可見性、有序性問題。但你是否好奇:同樣是加鎖,synchronized為何能實現(xiàn)“隱式管理”?鎖的狀態(tài)是如何存儲的?線程之間的鎖競爭是如何被JVM調(diào)度的?

本文將深入Java虛擬機(JVM)底層,從“鎖的載體(對象頭)”“鎖的觸發(fā)指令(字節(jié)碼)”“鎖的核心調(diào)度機制(monitor)”三個維度,完整拆解synchronized的實現(xiàn)邏輯,帶你從“會用”進階到“懂原理”,真正理解隱式鎖的本質(zhì)。

二、對象頭與Mark Word

Java中所有對象都可以作為synchronized的鎖對象,這并非偶然——每個Java對象在內(nèi)存中都包含一個“對象頭”結(jié)構(gòu),而對象頭中的“Mark Word”(標(biāo)記字)正是synchronized鎖狀態(tài)的核心存儲載體。簡單來說:synchronized的鎖,本質(zhì)是對對象頭Mark Word的狀態(tài)修改與競爭。

1. Java對象的內(nèi)存布局

在HotSpot虛擬機中,Java對象的內(nèi)存布局分為三部分:

  • 對象頭(Header) :存儲對象的核心元數(shù)據(jù),包括鎖狀態(tài)、線程ID、類指針等,是synchronized鎖機制的核心依賴;
  • 實例數(shù)據(jù)(Instance Data) :存儲對象的成員變量(包括從父類繼承的變量),是對象的核心業(yè)務(wù)數(shù)據(jù);
  • 對齊填充(Padding) :HotSpot虛擬機要求對象內(nèi)存大小必須是8字節(jié)的整數(shù)倍,對齊填充僅用于補全字節(jié)數(shù),無實際業(yè)務(wù)意義。

其中,對象頭是我們關(guān)注的重點,它又分為以下部分:

  • Mark Word :占4字節(jié)(32位虛擬機)或8字節(jié)(64位虛擬機),存儲鎖狀態(tài)、偏向線程ID、CAS指針、對象哈希碼、GC分代年齡等信息;
  • Klass Pointer(類指針) :占4字節(jié)(32位虛擬機)或8字節(jié)(64位虛擬機,開啟壓縮指針后為4字節(jié)),指向?qū)ο笏鶎兕惖腃lass對象,用于確定對象的類型。
  • Array Length(數(shù)組長度):占4字節(jié)(32位虛擬機)或8字節(jié)(64位虛擬機),存儲數(shù)組的元素個數(shù),數(shù)組長度是只有數(shù)組對象才有,普通對象沒有。

2. Mark Word的結(jié)構(gòu)與鎖狀態(tài)關(guān)聯(lián)

        Mark Word的結(jié)構(gòu)并非固定不變,而是會根據(jù)對象的“鎖狀態(tài)”動態(tài)變化——JDK1.6為synchronized引入鎖優(yōu)化后,鎖狀態(tài)分為4種:無鎖狀態(tài)、偏向鎖狀態(tài)、輕量級鎖狀態(tài)、重量級鎖狀態(tài)。不同狀態(tài)下,Mark Word存儲的信息不同,目的是在不同并發(fā)場景下平衡性能與安全性。

以64位HotSpot虛擬機為例,Mark Word的結(jié)構(gòu)如下圖所示:

其中各部分的含義如下:

  • lock:2位的鎖狀態(tài)標(biāo)記位,該標(biāo)記的值不同,整個 Mark Word表示的含義不同。biased_lock 和 lock一起,表達的鎖狀態(tài)含義如上圖所示;
  • biased_lock:對象是否啟用偏向鎖標(biāo)記,只占1個二進制位。為1時表示對象啟用偏向鎖,為0時表示對象沒有偏向鎖。lock 和 biased_lock共同表示對象處于什么鎖狀態(tài);
  • age:4位的Java對象年齡。
  • identity_hashcode:31位的對象標(biāo)識hashCode;
  • thread:持有偏向鎖的線程ID;
  • epoch:偏向鎖的時間戳;
  • ptr_to_lock_record:輕量級鎖狀態(tài)下,指向棧中鎖記錄的指針;
  • ptr_to_heavyweight_monitor:重量級鎖狀態(tài)下,指向?qū)ο蟊O(jiān)視器 Monitor的指針;

關(guān)鍵說明:

  • 鎖狀態(tài)由“偏向鎖標(biāo)志位”和“鎖標(biāo)志位”共同決定(例如:偏向鎖標(biāo)志位1+鎖標(biāo)志位01=偏向鎖;偏向鎖標(biāo)志位0+鎖標(biāo)志位00=輕量級鎖);
  • 隨著并發(fā)競爭加劇,鎖狀態(tài)會從“無鎖→偏向鎖→輕量級鎖→重量級鎖”逐步升級,且升級過程不可逆(一旦升級為重量級鎖,無法回退為輕量級鎖或偏向鎖);
  • Mark Word是synchronized鎖機制的“核心數(shù)據(jù)結(jié)構(gòu)”,所有鎖的獲取與釋放,本質(zhì)都是對Mark Word中鎖狀態(tài)的修改。

三、鎖的觸發(fā)與釋放

        synchronized是“隱式鎖”,其核心優(yōu)勢在于無需手動調(diào)用“lock()”“unlock()”方法——這種隱式管理的實現(xiàn),依賴于JVM在編譯階段為synchronized修飾的代碼插入特定的字節(jié)碼指令。不同用法(修飾方法、修飾代碼塊)對應(yīng)的字節(jié)碼實現(xiàn)略有差異,但核心邏輯一致。

1. 修飾代碼塊:monitorenter與monitorexit指令

        當(dāng)synchronized修飾代碼塊時,JVM會在代碼塊的“進入處”插入 monitorenter 指令,在“退出處”(包括正常退出和異常退出)插入 monitorexit 指令。這兩個指令是鎖獲取與釋放的直接觸發(fā)者。

代碼示例與字節(jié)碼分析:

public class SyncBlockDemo {
    private final Object lock = new Object();
    public void syncBlock() {
        // 同步代碼塊
        synchronized (lock) {
            System.out.println("進入同步代碼塊");
        }
    }
}

使用 javap -v SyncBlockDemo.class 命令反編譯,可得到 syncBlock 方法的字節(jié)碼(核心部分):

public void syncBlock();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0
         1: getfield      #2                  // Field lock:Ljava/lang/Object;
         4: dup
         5: monitorenter  // 進入同步代碼塊,獲取鎖(核心指令)
         6: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
         9: ldc           #4                  // String 進入同步代碼塊
        11: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        14: aload_1
        15: monitorexit   // 正常退出同步代碼塊,釋放鎖(核心指令)
        16: goto          24
        19: astore_2
        20: aload_1
        21: monitorexit   // 異常退出同步代碼塊,釋放鎖(核心指令)
        22: aload_2
        23: athrow
        24: return
      Exception table:
         from    to  target type
             6    16    19   any
}

字節(jié)碼核心邏輯解讀:

  • 0-4行:通過 getfield 指令獲取鎖對象 lock ,并通過 dup 指令復(fù)制一份鎖對象引用(用于后續(xù) monitorenter 和 monitorexit 操作);
  • 5行: monitorenter 指令——線程嘗試獲取鎖:若鎖未被持有,則將鎖的持有者設(shè)為當(dāng)前線程,鎖計數(shù)器+1;若鎖已被當(dāng)前線程持有,則鎖計數(shù)器+1(可重入性);若鎖被其他線程持有,則當(dāng)前線程阻塞;
  • 6-11行:執(zhí)行同步代碼塊的核心邏輯(打印語句);
  • 15行: monitorexit 指令(正常退出)——釋放鎖,鎖計數(shù)器-1,當(dāng)計數(shù)器減為0時,鎖被完全釋放,喚醒等待鎖的線程;
  • 19-23行:異常退出分支——JVM為同步代碼塊自動生成異常處理邏輯,確保即使發(fā)生異常,也能通過 monitorexit 釋放鎖,避免鎖泄漏。

關(guān)鍵結(jié)論: monitorenter 和 monitorexit 是synchronized修飾代碼塊的“鎖開關(guān)”,JVM通過這兩個指令實現(xiàn)鎖的獲取與釋放,且異常場景的鎖釋放由JVM自動保障。

2. 修飾方法:ACC_SYNCHRONIZED標(biāo)志位

        當(dāng)synchronized修飾實例方法或靜態(tài)方法時,JVM不會插入 monitorenter 和 monitorexit 指令,而是通過在方法的“訪問標(biāo)志(accessflags)”中添加 ACCSYNCHRONIZED 標(biāo)志位來實現(xiàn)鎖機制。

代碼示例與字節(jié)碼分析:

public class SyncMethodDemo {
    // 同步實例方法
    public synchronized void syncInstanceMethod() {
        System.out.println("進入同步實例方法");
    }
    // 同步靜態(tài)方法
    public static synchronized void syncStaticMethod() {
        System.out.println("進入同步靜態(tài)方法");
    }
}

反編譯后,方法的字節(jié)碼核心部分如下:

// 同步實例方法
public synchronized void syncInstanceMethod();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED  // 新增ACC_SYNCHRONIZED標(biāo)志位
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String 進入同步實例方法
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
// 同步靜態(tài)方法
public static synchronized void syncStaticMethod();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED  // 新增ACC_SYNCHRONIZED標(biāo)志位
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #5                  // String 進入同步靜態(tài)方法
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return

字節(jié)碼核心邏輯解讀:

  • 同步方法的字節(jié)碼中,沒有 monitorenter 和 monitorexit 指令,而是通過 ACC_SYNCHRONIZED 標(biāo)志位標(biāo)識“這是一個同步方法”;
  • 當(dāng)線程調(diào)用帶有 ACC_SYNCHRONIZED 標(biāo)志的方法時,JVM會自動嘗試獲取鎖:同步實例方法:鎖對象為當(dāng)前實例(this),獲取鎖的邏輯與 monitorenter 一致;同步靜態(tài)方法:鎖對象為當(dāng)前類的Class對象,獲取鎖的邏輯與 monitorenter 一致;
  • 方法執(zhí)行完成(正常return或異常拋出)時,JVM會自動釋放鎖,無需手動處理。

關(guān)鍵結(jié)論:synchronized修飾方法的鎖機制,本質(zhì)是JVM對 ACC_SYNCHRONIZED 標(biāo)志位的解析——將鎖的獲取與釋放邏輯嵌入到方法的調(diào)用與返回流程中,實現(xiàn)隱式管理。

四、核心鎖調(diào)度機制

        無論是 monitorenter 指令,還是 ACC_SYNCHRONIZED 標(biāo)志位,最終都依賴于“monitor”對象實現(xiàn)鎖的調(diào)度。monitor是操作系統(tǒng)層面的“互斥量(mutex)”的封裝,是synchronized重量級鎖的核心載體,負責(zé)管理線程的鎖競爭與等待。

1. monitor的本質(zhì)與結(jié)構(gòu)

monitor的本質(zhì)是一個“對象”,在HotSpot虛擬機中,它由C++語言實現(xiàn)(對應(yīng) ObjectMonitor 類)。每個Java對象在創(chuàng)建時,都會關(guān)聯(lián)一個monitor對象(可理解為“對象→monitor”的一對一映射),當(dāng)線程嘗試獲取鎖時,實際上是在競爭monitor的“所有權(quán)”。

ObjectMonitor 的核心結(jié)構(gòu)如下(簡化版):

class ObjectMonitor {
    // 持有當(dāng)前monitor的線程(鎖的所有者)
    Thread* owner;
    // 等待鎖的線程隊列(阻塞狀態(tài))
    Queue* EntryList;
    // 調(diào)用wait()后等待喚醒的線程隊列
    Queue* WaitSet;
    // 鎖計數(shù)器(實現(xiàn)可重入性)
    int count;
    // 遞歸鎖計數(shù)器(記錄重入次數(shù))
    int recursions;
};

2. 基于monitor的鎖競爭流程

        當(dāng)多個線程競爭同一把鎖時,JVM通過monitor的 owner 、 EntryList 、 WaitSet 三個核心組件實現(xiàn)調(diào)度,完整流程如下:

  • 初始狀態(tài) :monitor的 owner 為null, count 為0, EntryList 和 WaitSet 為空;
  • 線程1獲取鎖 :線程1執(zhí)行 monitorenter 指令(或調(diào)用同步方法),發(fā)現(xiàn)monitor的 owner 為null,直接成為 owner , count 置為1,進入臨界區(qū)執(zhí)行代碼;
  • 線程2競爭鎖 :線程2嘗試獲取鎖時,發(fā)現(xiàn)monitor的 owner 已為線程1,無法獲取,被JVM放入 EntryList 隊列,進入阻塞狀態(tài)(BLOCKED);
  • 線程1釋放鎖 :線程1執(zhí)行完臨界區(qū)代碼,執(zhí)行 monitorexit 指令(或方法返回), count 減為0,釋放monitor的 owner (置為null),并喚醒 EntryList 中的線程(如線程2);
  • 線程2再次競爭 :被喚醒的線程2重新嘗試獲取鎖,若此時monitor的 owner 為null,則成為新的 owner , count 置為1,進入臨界區(qū);若仍有其他線程競爭,則再次進入 EntryList 阻塞;
  • 線程調(diào)用wait()方法 :若線程1在持有鎖期間調(diào)用了 wait() 方法,則會釋放monitor的 owner , count 置為0,自身進入 WaitSet 隊列,進入等待狀態(tài)(WAITING);
  • 線程被notify()喚醒 :當(dāng)其他線程調(diào)用同一鎖對象的 notify() 或 notifyAll() 方法時,JVM會將 WaitSet 中的線程(如線程1)轉(zhuǎn)移到 EntryList 隊列,等待再次競爭鎖。

3. 重量級鎖的性能瓶頸根源

        在JDK1.6之前,synchronized直接使用上述monitor機制(即重量級鎖),導(dǎo)致性能較差。其核心瓶頸在于:

  • 線程狀態(tài)切換成本高 :線程從 EntryList 的阻塞狀態(tài)(BLOCKED)被喚醒后,需要從“內(nèi)核態(tài)”切換到“用戶態(tài)”,而狀態(tài)切換涉及操作系統(tǒng)內(nèi)核的調(diào)度,耗時較長;
  • 鎖競爭的排他性開銷 :即使只有兩個線程交替競爭鎖,也需要頻繁進行“阻塞→喚醒”的狀態(tài)切換,無法充分利用CPU資源。

這也是JDK1.6引入偏向鎖、輕量級鎖優(yōu)化的核心原因——在低并發(fā)場景下,避免使用重量級鎖的內(nèi)核態(tài)調(diào)度,提升鎖競爭效率。

五、可重入性的底層實現(xiàn)

        在上一文中我們提到,synchronized具備可重入性——同一線程可以多次獲取同一把鎖,不會因已持有鎖而阻塞。這一特性的底層實現(xiàn),依賴于monitor的 count (鎖計數(shù)器)和 recursions (遞歸鎖計數(shù)器)。

具體實現(xiàn)邏輯:

  • 線程第一次獲取鎖時,monitor的 owner 設(shè)為當(dāng)前線程, count 置為1, recursions 置為0;
  • 線程再次獲取同一把鎖時(如同步方法調(diào)用同步方法),JVM檢測到當(dāng)前線程已是monitor的 owner ,則直接將 count 加1, recursions 加1(記錄重入次數(shù));
  • 線程每次釋放鎖時, count 減1;
  • 當(dāng) count 減為0時,說明線程已完全釋放鎖, owner 置為null,其他線程可競爭。

示例驗證:

public class ReentrantDemo {
    public synchronized void methodA() {
        System.out.println("進入methodA");
        methodB(); // 同一線程調(diào)用同步方法,重入鎖
    }
    public synchronized void methodB() {
        System.out.println("進入methodB");
    }
    public static void main(String[] args) {
        new ReentrantDemo().methodA();
    }
}

執(zhí)行流程:

  • 線程調(diào)用 methodA() ,獲取鎖,monitor的 count=1 ;
  • 線程在 methodA() 中調(diào)用 methodB() ,再次獲取同一把鎖,monitor的 count=2 ;
  • methodB() 執(zhí)行完成,釋放鎖, count=1 ;
  • methodA() 執(zhí)行完成,釋放鎖, count=0 ,鎖完全釋放。

關(guān)鍵結(jié)論:可重入性的核心是“鎖計數(shù)器”——通過計數(shù)記錄線程的重入次數(shù),確保線程只有在完全釋放所有重入鎖后,才會讓出鎖的所有權(quán)。

六、內(nèi)存可見性的底層保障

        在上一文中我們提到,synchronized能保證內(nèi)存可見性——一個線程對共享變量的修改,會被后續(xù)獲取同一把鎖的線程及時感知。這一特性的底層實現(xiàn),依賴于JVM在鎖的獲取與釋放過程中插入的“內(nèi)存屏障”。

1. 內(nèi)存屏障的核心作用

        內(nèi)存屏障是CPU層面的指令,用于禁止指令重排序,并強制刷新工作內(nèi)存與主內(nèi)存的數(shù)據(jù)。JVM通過插入內(nèi)存屏障,確保:

  • 線程對共享變量的修改,必須同步到主內(nèi)存;
  • 線程讀取共享變量時,必須從主內(nèi)存加載最新數(shù)據(jù)。

2. synchronized的內(nèi)存屏障插入規(guī)則

JVM為synchronized的鎖獲取與釋放過程,制定了嚴(yán)格的內(nèi)存屏障插入規(guī)則:

  • 鎖獲取時 :在 monitorenter 指令(或同步方法調(diào)用)后,插入“LoadLoad屏障”和“LoadStore屏障”:
  • LoadLoad屏障:禁止后續(xù)的讀操作與當(dāng)前讀操作重排序;
  • LoadStore屏障:禁止后續(xù)的寫操作與當(dāng)前讀操作重排序;
  • 核心效果:強制線程從主內(nèi)存加載共享變量的最新數(shù)據(jù),避免讀取舊值。
  • 鎖釋放時 :在 monitorexit 指令(或同步方法返回)前,插入“StoreStore屏障”和“StoreLoad屏障”:
  • StoreStore屏障:禁止當(dāng)前寫操作與后續(xù)寫操作重排序;
  • StoreLoad屏障:禁止當(dāng)前寫操作與后續(xù)讀操作重排序,并強制將工作內(nèi)存中的數(shù)據(jù)同步到主內(nèi)存;
  • 核心效果:確保線程對共享變量的修改已同步到主內(nèi)存,讓其他線程可見。

3. 與volatile的可見性機制對比

synchronized與volatile都能保證內(nèi)存可見性,但實現(xiàn)邏輯不同:

特性

synchronized

volatile

可見性實現(xiàn)方式

通過鎖獲取/釋放時插入的內(nèi)存屏障,間接保證可見性

直接在寫操作后插入StoreLoad屏障,讀操作前插入LoadLoad屏障,直接保證可見性

額外保障

同時保證原子性、有序性

僅保證可見性、有序性,不保證原子性

適用場景

臨界區(qū)代碼(多操作組合)

單個共享變量的讀/寫操作

七、總結(jié)

        本文從JVM底層視角,完整拆解了synchronized的實現(xiàn)邏輯,核心可總結(jié)為“三個核心載體+一個調(diào)度機制”:

  • 鎖的存儲載體 :對象頭的Mark Word,通過動態(tài)修改鎖狀態(tài)(無鎖→偏向鎖→輕量級鎖→重量級鎖)適配不同并發(fā)場景;
  • 鎖的觸發(fā)指令 :修飾代碼塊時通過 monitorenter / monitorexit 指令,修飾方法時通過 ACC_SYNCHRONIZED 標(biāo)志位,實現(xiàn)隱式鎖管理;
  • 鎖的調(diào)度機制 :基于monitor對象( ObjectMonitor )的 owner 、 EntryList 、 WaitSet 組件,實現(xiàn)線程的鎖競爭與等待喚醒;
  • 可見性與可重入性保障 :通過內(nèi)存屏障保證可見性,通過monitor的鎖計數(shù)器實現(xiàn)可重入性。

        理解這些底層原理,能幫你更深刻地理解synchronized的性能特性——為何JDK1.6要引入鎖優(yōu)化?為何偏向鎖適合單線程場景?為何高并發(fā)下synchronized性能會下降?這些問題,我們將在第3篇“synchronized鎖優(yōu)化深度解析”中詳細解答。

        下一篇文章,我們將聚焦JDK1.6的鎖優(yōu)化機制,深入剖析偏向鎖、輕量級鎖、重量級鎖的實現(xiàn)細節(jié)與升級流程,帶你理解synchronized性能提升的核心邏輯,敬請關(guān)注!

到此這篇關(guān)于synchronized底層原理之JVM層面的鎖實現(xiàn)細節(jié)與流程的文章就介紹到這了,更多相關(guān)synchronized JVM層面內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java解析JSON的六種方案

    Java解析JSON的六種方案

    這篇文章介紹了 6 種 JSON 解析方案,包括 Jackson、Gson、FastJSON、JsonPath、、手動解析,分別闡述了它們的功能特點、代碼示例、高級功能、優(yōu)缺點及適用場景,感興趣的小伙伴跟著小編一起來看看吧
    2025-01-01
  • 使用SpringBoot請求方式和訪問靜態(tài)頁面

    使用SpringBoot請求方式和訪問靜態(tài)頁面

    SpringBoot支持多種請求方式,包括GET、RESTful、分頁列表等,常用框架如阿里fastjson、谷歌gson用于JavaBean序列化為Json,性能上Jackson最快,SpringBoot目錄結(jié)構(gòu)包括src/main/java、src/main/resources等
    2025-01-01
  • 深入理解java線程通信

    深入理解java線程通信

    開發(fā)中不免會遇到需要所有子線程執(zhí)行完畢通知主線程處理某些邏輯的場景。或者是線程 A 在執(zhí)行到某個條件通知線程 B 執(zhí)行某個操作。下面我們來一起學(xué)習(xí)如何解決吧
    2019-05-05
  • Java實現(xiàn)畫圖的詳細步驟(完整代碼)

    Java實現(xiàn)畫圖的詳細步驟(完整代碼)

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著Java實現(xiàn)畫圖的詳細步驟展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • JAVA返回PDF文件流并進行下載的實現(xiàn)方法

    JAVA返回PDF文件流并進行下載的實現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于JAVA返回PDF文件流并進行下載的實現(xiàn)方法,PDF文件流下載是通過HTTP協(xié)議將服務(wù)器上的PDF文件以流的方式發(fā)送給客戶端,供客戶端保存到本地磁盤或直接在瀏覽器中打開,需要的朋友可以參考下
    2024-02-02
  • Java單例模式的6種實現(xiàn)方式詳解

    Java單例模式的6種實現(xiàn)方式詳解

    這篇文章主要介紹了Java單例模式的6種實現(xiàn)方式的相關(guān)資料,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-09-09
  • Springboot詳解整合SpringSecurity實現(xiàn)全過程

    Springboot詳解整合SpringSecurity實現(xiàn)全過程

    Spring Security基于Spring開發(fā),項目中如果使用Springboot作為基礎(chǔ),配合Spring Security做權(quán)限更加方便,而Shiro需要和Spring進行整合開發(fā)。因此作為spring全家桶中的Spring Security在java領(lǐng)域很常用
    2022-07-07
  • SpringBoot2種單元測試方法解析

    SpringBoot2種單元測試方法解析

    這篇文章主要介紹了SpringBoot2種單元測試方法解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • MyBatis學(xué)習(xí)教程之開發(fā)Dao的方法教程

    MyBatis學(xué)習(xí)教程之開發(fā)Dao的方法教程

    這篇文章主要給大家介紹了關(guān)于MyBatis開發(fā)Dao的相關(guān)資料,使用Mybatis開發(fā)Dao,通常有兩個方法,即原始Dao開發(fā)方法和Mapper接口開發(fā)方法。文中通過示例代碼介紹的非常詳細,需要的朋友們下面來一起看看吧。
    2017-07-07
  • JDK21無法導(dǎo)入TimeUnit類的解決辦法

    JDK21無法導(dǎo)入TimeUnit類的解決辦法

    這篇文章主要給大家介紹了關(guān)于JDK21無法導(dǎo)入TimeUnit類的解決辦法,TimeUnit是java.util.concurrent包下面的一個類,TimeUnit提供了可讀性更好的線程暫停操作,通常用來替換Thread.sleep(),需要的朋友可以參考下
    2024-01-01

最新評論

林西县| 隆子县| 岳西县| 万安县| 噶尔县| 黄龙县| 金华市| 龙井市| 柘城县| 泸水县| 当雄县| 峨眉山市| 商洛市| 巴青县| 灌阳县| 府谷县| 巴塘县| 桂东县| 常山县| 原平市| 吴桥县| 会东县| 郯城县| 余江县| 平罗县| 时尚| 百色市| 朝阳县| 郁南县| 岑溪市| 古交市| 呼图壁县| 鄂尔多斯市| 田东县| 大城县| 当阳市| 泸西县| 乡宁县| 安远县| 成武县| 西盟|