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

Java中的synchronized鎖膨脹詳解

 更新時間:2024年01月10日 09:08:14   作者:愛coding的同學(xué)  
這篇文章主要介紹了Java中的synchronized鎖膨脹詳解,正常創(chuàng)建的對象,狀態(tài)為無鎖,對象頭的Mark?Word?中主要記錄了?對象的年齡,也就是經(jīng)歷了多少次GC還存活下來,需要的朋友可以參考下

1. 基本概念

Java對象頭

Java對象的對象頭信息中的 Mark Word 主要是用來記錄對象的鎖信息的。

現(xiàn)在看一下 Mark Word 的對象頭信息。如下:

在這里插入圖片描述

其實可以根據(jù) mark word 的后3位就可以判斷出當(dāng)前的鎖是屬于哪一種鎖。注意:表格中的正常鎖其實就是無鎖狀態(tài)了。

2. 幾種鎖以及原理

無鎖

正常創(chuàng)建的對象,狀態(tài)為無鎖。對象頭的Mark Word 中主要記錄了 對象的年齡,也就是經(jīng)歷了多少次GC還存活下來。

偏向鎖

對象頭的Mark Word 中記錄的信息比正常鎖多的是 記錄了線程的信息,也就是線程的id。偏向鎖,字面意思就是比較偏心,偏向于某個線程。

偏向鎖加鎖原理

經(jīng)過分析可以看到,thread 字段剛開始的時候為0。工作原理是 cas(thread,0,當(dāng)前線程), 也就是判斷當(dāng)前的 thread的值如果是0的話,就賦值為當(dāng)前線程。如果cas 拿鎖失敗了,那么有倆種情況。

重入

當(dāng)前線程已經(jīng)是偏向鎖的持有者了,那么只需要判斷 thread 字段是否就是當(dāng)前線程,如果是的話,其實就是當(dāng)前線程已經(jīng)拿到這把鎖了。那么此時就會在棧中創(chuàng)建lockRecord。因為棧是線程私有的。lockRecord 其實包含倆部分的內(nèi)容,第一部分內(nèi)容和鎖對象的 markword中的對象是完全一樣的。記為M區(qū)。第二部分是記錄了當(dāng)前對象,也就是加鎖對象的指針。記為O區(qū)。在第一次加鎖的時候,是不需要創(chuàng)建 lockRecord的。只有在重入的時候,才需要創(chuàng)建 lockRecord的。

其它線程持有鎖

那么此時就會升級為輕量級鎖。

偏向鎖解鎖原理

解鎖過程非常簡單,只需要在當(dāng)前線程的棧上刪除最近的lockRecord對象就可以了。因為重入的時候是不斷的創(chuàng)建這些lockRecord對象的。

輕量級鎖

主要是將鎖對象的Mark Word更新為指向Lock Record的指針,也就是鎖記錄。注意,這個鎖記錄是在棧上的。

輕量級鎖加鎖原理

線程在自己的棧楨中創(chuàng)建鎖記錄 LockRecord。

在這里插入圖片描述

將鎖對象的對象頭中的MarkWord復(fù)制到線程的剛剛創(chuàng)建的鎖記錄中。

將鎖對象的對象頭的MarkWord替換為指向鎖記錄的指針。也就是進(jìn)行cas操作。cas(ptr, null, lockRecord)。也就是如果對象頭的ptr指針如果為空,那么就賦值為當(dāng)前的lockRecord對象。并將線程棧幀中的Lock Record里的owner指針指向Object的 Mark Word。如果賦值成功了,那么就可以認(rèn)為加鎖成功了。

在這里插入圖片描述

如果加鎖失敗了,也有倆種情況。

重入。

就是ptr 指向的是另外的一個lockRecord對象,但是也是當(dāng)前線程創(chuàng)建的。也就是在當(dāng)前線程的棧上是可以找到這個lockRecord對象。首先在棧上檢查是否可以找到這個鎖對象。如果可以找到,就是重入。如果是重入,那么就需要將鎖記錄中的Owner指針指向鎖對象。

其它線程持有鎖

那么就進(jìn)入重量級鎖。

輕量級鎖解鎖原理

釋放鎖的時候,從棧上進(jìn)行掃描,從后往前 找到最近的lockRecord,刪除。

重量級鎖

主要是指向一個monitor 對象。

分析如下: synchronized重量級鎖解析

3. 看一段程序,看一下鎖是如何進(jìn)行演變的。

package org.example;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
/**
 * @author frank wy170862@alibaba-inc.com
 * @date 2020-02-24
 */
public class A {
    public static void main(String[] args) throws Exception {
        test2();
    }
    /**
     * 一、正常創(chuàng)建的對象,狀態(tài)為無鎖,觀察hashcode和age的變化。hashcode 的計算是惰性的。剛開始的時候,對象的hashcode是0。只有在計算了hashcode以后,才會將hashcode存儲到對象頭,下次取hashcode的時候,就可以直接從對象頭中取出hashcode了。
     *
     * 鎖狀態(tài):無鎖,hashCode:0,age: 0
     * ---------------
     *
     * 運行hashcode方法,得到hashcode:648129364
     * 鎖狀態(tài):無鎖,hashCode:648129364,age: 0
     * ---------------
     *
     * [GC (System.gc()) [PSYoungGen: 6568K->1095K(76288K)] 6568K->1103K(251392K), 0.0017301 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
     * [Full GC (System.gc()) [PSYoungGen: 1095K->0K(76288K)] [ParOldGen: 8K->932K(175104K)] 1103K->932K(251392K), [Metaspace: 3084K->3084K(1056768K)], 0.0054386 secs] [Times: user=0.02 sys=0.01, real=0.01 secs]
     * 運行一次gc,obj的age+1
     * 鎖狀態(tài):無鎖,hashCode:648129364,age: 1
     * ---------------
     *  @throws Exception
     */
    private static void test1() throws Exception {
        Object a = new Object();
        printLockHeader(a);
        System.out.println("運行hashcode方法,得到hashcode:" + a.hashCode());;
        printLockHeader(a);
        System.gc();
        System.out.println("運行一次gc,obj的age+1");
        // sleep 1s 讓gc完成,但是不一定能100%觸發(fā)gc,可以配合添加運行參數(shù) -XX:+PrintGCDetails,觀察確實gc了
        Thread.sleep(1000);
        printLockHeader(a);
    }
    /**
     * 二、正常創(chuàng)建的對象,狀態(tài)為無鎖,無鎖狀態(tài)直接加鎖會變成輕量鎖
     *
     * 鎖狀態(tài):無鎖,hashCode:0,age: 0
     * ---------------
     *
     * 對a加鎖后
     * 鎖狀態(tài):輕量級鎖,LockRecord地址:1c00010c6e28
     * ---------------
     * @throws Exception
     */
    private static void test2() throws Exception {
        Object a = new Object();
        printLockHeader(a);
        synchronized (a){
            System.out.println("對a加鎖后");
            printLockHeader(a);
        }
    }
    /**
     * 三、程序啟動一定時間后,正常創(chuàng)建的對象,狀態(tài)為偏向鎖且thread為0,此時加鎖默認(rèn)為偏向鎖
     * 一段時間一般是幾秒,-XX:BiasedLockingStartupDelay=0可以指定默認(rèn)就使用偏向鎖,而不是無鎖
     *
     * 鎖狀態(tài):偏向鎖,thread:0,epoch: 0,age: 0
     * ---------------
     *
     * 對a加鎖后
     * 鎖狀態(tài):偏向鎖,thread:137069895700,epoch: 0,age: 0
     * ---------------
     *
     * 偏向鎖重入后
     * 鎖狀態(tài):偏向鎖,thread:137069895700,epoch: 0,age: 0
     * ---------------
     * @throws Exception
     */
    private static void test3() throws Exception {
        Thread.sleep(5*1000);
        Object a = new Object();
        printLockHeader(a);
        synchronized (a){
            System.out.println("對a加鎖后");
            printLockHeader(a);
            System.out.println("偏向鎖重入后");
            synchronized (a){
                printLockHeader(a);
            }
        }
    }
    /**
     * 四、基于三,當(dāng)另一個線程嘗試使用對象鎖的時候,升級為輕量鎖
     *
     * 鎖狀態(tài):偏向鎖,thread:0,epoch: 0,age: 0
     * ---------------
     *
     * 線程1對a加鎖后
     * 鎖狀態(tài):偏向鎖,thread:137122299998,epoch: 0,age: 0
     * ---------------
     *
     * 鎖釋放了
     * 線程2對a加鎖后
     * 鎖狀態(tài):輕量級鎖,LockRecord地址:1c00015e6a18
     * ---------------
     * @throws Exception
     */
    private static void test4() throws Exception {
        Thread.sleep(5*1000);
        Object a = new Object();
        printLockHeader(a);
        new Thread(
                ()->{
                    synchronized (a){
                        System.out.println("線程1對a加鎖后");
                        try {
                            printLockHeader(a);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        ).start();
        // 中間sleep1s,保證鎖釋放掉,使兩個線程不會有競爭關(guān)系
        Thread.sleep(1000);
        System.out.println("鎖釋放了");
        new Thread(
                ()->{
                    synchronized (a){
                        System.out.println("線程2對a加鎖后");
                        try {
                            printLockHeader(a);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
    }
    /**
     * 五、基于四,當(dāng)產(chǎn)生競爭的時候偏向鎖直接升級為重量級鎖
     *
     * 鎖狀態(tài):偏向鎖,thread:0,epoch: 0,age: 0
     * ---------------
     *
     * 線程1對a加鎖后
     * 鎖狀態(tài):偏向鎖,thread:137025283340,epoch: 0,age: 0
     * ---------------
     *
     * 線程2對a加鎖后
     * 鎖狀態(tài):重量級鎖,Monitor地址:1fe758800a02
     * ---------------
     * @throws Exception
     */
    private static void test5() throws Exception {
        Thread.sleep(5*1000);
        Object a = new Object();
        printLockHeader(a);
        new Thread(
                ()->{
                    synchronized (a){
                        System.out.println("線程1對a加鎖后");
                        try {
                            printLockHeader(a);
                            Thread.sleep(1000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
        new Thread(
                ()->{
                    synchronized (a){
                        System.out.println("線程2對a加鎖后");
                        try {
                            printLockHeader(a);
                            Thread.sleep(1000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
    }
    /**
     * 六、四+五 演示偏向-輕量-重量過程
     *
     * 鎖狀態(tài):偏向鎖,thread:0,epoch: 0,age: 0
     * ---------------
     *
     * 線程1對a加鎖后
     * 鎖狀態(tài):偏向鎖,thread:137272648594,epoch: 0,age: 0
     * ---------------
     *
     * 鎖釋放
     * 線程2對a加鎖后
     * 鎖狀態(tài):輕量級鎖,LockRecord地址:1c0001b43e18
     * ---------------
     *
     * 鎖釋放
     * 線程3對a加鎖后
     * 鎖狀態(tài):輕量級鎖,LockRecord地址:1c0001b43e18
     * ---------------
     *
     * 線程4對a加鎖后
     * 鎖狀態(tài):重量級鎖,Monitor地址:1ff616600f02
     * ---------------
     * @throws Exception
     */
    private static void test6() throws Exception {
        Thread.sleep(5*1000);
        Object a = new Object();
        printLockHeader(a);
        new Thread(
                ()->{
                    synchronized (a){
                        System.out.println("線程1對a加鎖后");
                        try {
                            printLockHeader(a);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        ).start();
        // 中間sleep1s,使線程不會有競爭關(guān)系
        Thread.sleep(1000);
        System.out.println("鎖釋放");
        new Thread(
                ()->{
                    synchronized (a){
                        System.out.println("線程2對a加鎖后");
                        try {
                            printLockHeader(a);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
        // 中間sleep1s,使線程不會有競爭關(guān)系
        Thread.sleep(1000);
        System.out.println("鎖釋放");
        new Thread(
                ()->{
                    synchronized (a){
                        System.out.println("線程3對a加鎖后");
                        try {
                            printLockHeader(a);
                            Thread.sleep(1000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
        // 此時不再sleep,使線程必然發(fā)生競爭,升級為重量級鎖
        new Thread(
                ()->{
                    synchronized (a){
                        System.out.println("線程4對a加鎖后");
                        try {
                            printLockHeader(a);
                            Thread.sleep(1000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
    }
    private static Unsafe getUnsafe() throws Exception {
        Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
        Field field = unsafeClass.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        return  (Unsafe) field.get(null);
    }
    private static void printLockHeader(Object obj) throws Exception {
        Unsafe us = getUnsafe();
        StringBuilder sb = new StringBuilder();
        int status = us.getByte(obj, 0L) & 0B11;
        // 0 輕量級 1 無鎖或偏向 2 重量級 3 GC標(biāo)記
        switch (status){
            case 0:
                // ptr_to_lock_record:62|lock:2
                long ptrToLockRecord =
                        (byteMod(us.getByte(obj, 0L))>>2) +
                                (byteMod(us.getByte(obj, 1L))<<6) +
                                (byteMod(us.getByte(obj, 2L))<<14) +
                                (byteMod(us.getByte(obj, 3L))<<22) +
                                (byteMod(us.getByte(obj, 4L))<<30) +
                                (byteMod(us.getByte(obj, 5L))<<38) +
                                (byteMod(us.getByte(obj, 6L))<<46) +
                                (byteMod(us.getByte(obj, 7L))<<54);
                sb.append("鎖狀態(tài):輕量級鎖,LockRecord地址:")
                        .append(Long.toHexString(ptrToLockRecord))
                ;
                break;
            case 1:
                boolean biased = (us.getByte(obj, 0L)&4) == 4;
                if(!biased){
                    // unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2
                    int hashCode = (int)(byteMod(us.getByte(obj, 1L))
                            + (byteMod(us.getByte(obj, 2L))<<8)
                            + (byteMod(us.getByte(obj, 3L))<<16)
                            + ((byteMod(us.getByte(obj, 4L))&Integer.MAX_VALUE) <<24))
                            ;
                    int age = (us.getByte(obj,0L)>>3)&0B1111;
                    sb.append("鎖狀態(tài):無鎖,hashCode:")
                            .append(hashCode)
                            .append(",age: ")
                            .append(age);
                }else{
                    //thread:54|epoch:2|unused:1| age:4 | biased_lock:1 | lock:2
                    long thread = (byteMod(us.getByte(obj, 1L))>>2) +
                            (byteMod(us.getByte(obj, 2L))<<6) +
                            (byteMod(us.getByte(obj, 3L))<<14) +
                            (byteMod(us.getByte(obj, 4L))<<22) +
                            (byteMod(us.getByte(obj, 5L))<<30) +
                            (byteMod(us.getByte(obj, 6L))<<38) +
                            (byteMod(us.getByte(obj, 7L))<<46);
                    ;
                    int epoch = us.getByte(obj, 1L) & 0B11;
                    int age = (us.getByte(obj,0L)>>3)&0B1111;
                    sb.append("鎖狀態(tài):偏向鎖,thread:")
                            .append(thread)
                            .append(",epoch: ")
                            .append(epoch)
                            .append(",age: ")
                            .append(age);
                }
                break;
            case 2:
                // ptr_to_heavyweight_monitor:62| lock:2
                long ptrToMonitor =
                        (byteMod(us.getByte(obj, 0L))>>2) +
                                (byteMod(us.getByte(obj, 1L))<<6) +
                                (byteMod(us.getByte(obj, 2L))<<14) +
                                (byteMod(us.getByte(obj, 3L))<<22) +
                                (byteMod(us.getByte(obj, 4L))<<30) +
                                (byteMod(us.getByte(obj, 5L))<<38) +
                                (byteMod(us.getByte(obj, 6L))<<46) +
                                (byteMod(us.getByte(obj, 7L))<<54);
                sb.append("鎖狀態(tài):重量級鎖,Monitor地址:")
                        .append(Long.toHexString(ptrToMonitor))
                ;
                break;
            case 3:
                sb.append("鎖狀態(tài):GC標(biāo)記");
                break;
            default:
                break;
        }
        if(obj instanceof Object[]){
            int arrLen = us.getInt(obj, 3L);
            sb.append("對象為數(shù)組類型,數(shù)組長度:")
                    .append(arrLen);
        }
        sb.append("\n").append("---------------").append("\n");
        System.out.println(sb.toString());
    }
    private static long byteMod(byte b){
        if(b>=0){
            return b;
        }
        return b + 256;
    }
}

4. 總結(jié)

剛開始,程序開始運行的時候,創(chuàng)建的對象都屬于無鎖對象。程序運行一段時間后,一段時間一般指的是4秒鐘,創(chuàng)建的對象屬于偏向鎖對象。無鎖狀態(tài)下直接加鎖會變?yōu)檩p量級鎖。偏向鎖狀態(tài)下的對象,加鎖的話,會對當(dāng)前線程有一個偏向。如果此時再有另外的一個線程過來申請鎖,那么就會升級為輕量級鎖對象。輕量級鎖下,如果存在競爭,那么一定會升級為重量級鎖。當(dāng)然,偏向鎖狀態(tài)下,如果存在競爭,也會升級為重量級鎖。

總結(jié)起來就是:如果存在競爭,那么一定會升級為重量級鎖。如果存在另外一個線程想要拿到這把鎖,就會升級為輕量級鎖。偏向鎖和輕量級鎖的區(qū)別是:輕量級鎖是可以另外一個線程來拿鎖,也就是一個線程釋放掉鎖以后,另外一個線程可以來拿鎖,這就是輕量級鎖。如果一個線程釋放掉鎖以后,另外一個線程拿不到這把鎖,那么就屬于偏向鎖。

到此這篇關(guān)于Java中的synchronized鎖膨脹詳解的文章就介紹到這了,更多相關(guān)synchronized鎖膨脹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring中過濾器(Filter)和攔截器(Interceptor)的區(qū)別和聯(lián)系解析

    Spring中過濾器(Filter)和攔截器(Interceptor)的區(qū)別和聯(lián)系解析

    在我們?nèi)粘5拈_發(fā)中,我們經(jīng)常會用到Filter和Interceptor,這篇文章主要介紹了Spring中過濾器(Filter)和攔截器(Interceptor)的區(qū)別和聯(lián)系?,需要的朋友可以參考下
    2022-10-10
  • Unity2019-2020 個人版官方免費激活詳細(xì)方法

    Unity2019-2020 個人版官方免費激活詳細(xì)方法

    這篇文章主要介紹了Unity2019-2020 個人版官方免費激活詳細(xì)方法,激活方法分位兩種一種是激活新許可證,一種是手動激活,感興趣的朋友跟隨小編一起看看吧
    2021-04-04
  • SVN出現(xiàn)提示org.apache.subversion.javahl.ClientException: Attempted to lock an already-locked dir解決方案

    SVN出現(xiàn)提示org.apache.subversion.javahl.ClientException: Attempt

    這篇文章主要介紹了SVN出現(xiàn)提示org.apache.subversion.javahl.ClientException: Attempted to lock an already-locked dir解決方案的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • 基于Java開發(fā)一個極簡版敏感詞檢測工具

    基于Java開發(fā)一個極簡版敏感詞檢測工具

    這篇文章主要為大家詳細(xì)介紹了如何基于Java開發(fā)一個極簡版敏感詞檢測工具,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-08-08
  • 關(guān)于maven下載慢的問題

    關(guān)于maven下載慢的問題

    這篇文章主要介紹了關(guān)于maven下載慢的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 入門java的第一步HelloWorld

    入門java的第一步HelloWorld

    這篇文章主要介紹了入門java的第一步-Hello,World,文中通過示例代碼介紹的非常詳細(xì),對大家的java初步學(xué)習(xí)具有一定的學(xué)習(xí)價值,需要的朋友可以參考下
    2021-04-04
  • Spring JDBC的使用方法詳解

    Spring JDBC的使用方法詳解

    這篇文章主要介紹了Spring JDBC的使用方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • Java+Redis撤銷重做功能實現(xiàn)

    Java+Redis撤銷重做功能實現(xiàn)

    這篇文章主要介紹了Java+Redis實現(xiàn)撤銷重做功能,需要考慮撤銷的最大步數(shù),撤銷之后穿插著其他操作則不能再重做,所以引入分布式鎖Redisson進(jìn)行加鎖處理,防止對圖表的操作有并發(fā)請求導(dǎo)致處理撤銷邏輯混亂,感興趣的朋友跟隨小編一起看看吧
    2023-05-05
  • Jmeter使用接口傳遞數(shù)據(jù)過程圖解

    Jmeter使用接口傳遞數(shù)據(jù)過程圖解

    這篇文章主要介紹了Jmeter使用接口傳遞數(shù)據(jù)過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-05-05
  • 一文詳解Maven的setting文件

    一文詳解Maven的setting文件

    maven?是目前java?常見的一款包管理工具,通過?maven?我們可以很方便的對項目進(jìn)行編譯、打包、部署等操作,本文將詳細(xì)帶大家了解一下Maven?setting文件,需要的朋友可以參考下
    2024-02-02

最新評論

姜堰市| 临江市| 潞城市| 元江| 平和县| 响水县| 广饶县| 英超| 桂林市| 云林县| 阜宁县| 鄂尔多斯市| 姚安县| 汤阴县| 大竹县| 宜章县| 台江县| 玉门市| 定陶县| 许昌市| 泰兴市| 游戏| 广河县| 巴彦县| 慈利县| 平和县| 会泽县| 渭南市| 天等县| 中江县| 大埔县| 德昌县| 东城区| 丹阳市| 蓬溪县| 清徐县| 资阳市| 定州市| 衡东县| 常宁市| 大安市|