Synchronized 鎖 批量重偏向 和批量撤銷


 
一、JVM參數設置參考
  1. 關閉延遲:-XX:BiasedLockingStartupDelay=0
  2. 設置JVM關閉偏向鎖:-XX:UseBiasedLocking=false
  3. 打印JVM啟動參數: -XX:+PrintFlagsFinal
 
二、釋義
1 批量重偏向鎖:當對某個類的對象偏向鎖批量撤銷20次,則偏向鎖認為,后面的鎖需要重新偏向新的線程(批量重偏向)
2 批量撤銷:當某個類的對象的偏向鎖累計被撤銷到閾值40次(從40次開始),則偏向鎖認為偏向鎖撤銷過於頻繁,則后面的對象包括新生成的對象(標識為101和001)如果需要使用鎖,則直接輕量級鎖,不在使用偏向鎖(即禁用了偏向鎖)
 
三、打印JVM設置
  
 intx BiasedLockingBulkRebiasThreshold          = 20                                  {product}
     intx BiasedLockingBulkRevokeThreshold          = 40                                  {product}
四、代碼案例
 
static int count=39;//39 則正好是經歷了,40次偏向鎖撤銷,以后新創建的對象為無鎖不可偏向標識,那加鎖則直接為輕量級鎖(撤銷了偏向鎖這個步驟)
  
package com.test;


import org.openjdk.jol.info.ClassLayout;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;


/**
* Hello world!
* -XX:+PrintFlagsFinal
* -Xms1g -Xmx1g  -XX:+PrintGCDetails -XX:BiasedLockingStartupDelay=0 偏向延遲關閉參數
*/


public class Test4
{
    static  Thread t1=null;
    static  Thread t2 = null;
    static  Thread t3 = null;


    static int count=39;//39 則正好是經歷了,40次偏向鎖撤銷,以后新創建的對象為無鎖不可偏向標識,那加鎖則直接為輕量級鎖(撤銷了偏向鎖這個步驟)


    public static void main( String[] args ) throws InterruptedException {


//        System.out.println(String.format(" 新對象鎖標識:%s ", ClassLayout.parseInstance(new B()).toPrintableTest()));
        B b2 = new B();
        //保存鎖對象列表
        List<B> list = new ArrayList<>();
        //第一個線程
        t1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i <count ; i++) {
                    B b = new B();
                    list.add(b);
                    System.out.println(String.format("線程名稱 %s 執行的次數 %d ", Thread.currentThread().getName(),i));
                    System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
                    synchronized (b){
                        //打印第一個線程加鎖后 ,對象頭變化
                        System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
                    }
                    System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
                }
                LockSupport.unpark(t2);
            }
        };


        t2  = new Thread( ){
            @Override
            public void run() {
                LockSupport.park();
                System.out.println("線程2開始執行======");
                for (int i = 0; i <count ; i++) {
                    System.out.println(String.format("線程名稱 %s 執行的次數 %d ", Thread.currentThread().getName(),i));
                    B b = list.get(i);
                    System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
                    synchronized (list.get(i)){
                        //打印第二個線程對對象加鎖,對象頭變化(線程前20次為偏向鎖升級輕量級鎖,從20次開始偏向鎖偏向線程t2,發生線程重偏向)
                        System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
                    }
                    System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
                }
                LockSupport.unpark(t3);
            }
        };


        t3 = new Thread(()->{
            LockSupport.park();
            System.out.println("線程3開始執行========================");
            for (int i = 0; i <count ; i++) {
                System.out.println(String.format("線程名稱 %s 執行的次數 %d ", Thread.currentThread().getName(),i));
                B b = list.get(i);
                System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
                synchronized (b){
                    //線程從20個開始進行偏向鎖撤銷直到發生撤銷40次到達閾值,則后面的對象發生 偏向鎖 批量撤銷
                    System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
                }
                System.out.println(ClassLayout.parseInstance(b).toPrintableTest());
            }
        });


        t1.setName("線程t1 ");
        t2.setName("線程t2 ");
        t3.setName("線程t3 ");


        t1.start();
        t2.start();
        t3.start();
        t1.join();
        t2.join();
        t3.join();


        System.out.println("= 主線程新====================");
        //發生批量撤銷后線程加鎖,轉換為輕量級鎖
        System.out.println(String.format(" 新對象鎖標識:%s ", ClassLayout.parseInstance(b2).toPrintableTest()));
        synchronized (b2){
            System.out.println(String.format(" 新對象鎖標識:%s ", ClassLayout.parseInstance(b2).toPrintableTest()));
        }
    }
}
View Code

 

打印結果:
  1) 線程t1打印結果為偏向鎖-取了38個打印結果:
      
1 線程名稱 線程t1  執行的次數 38
2       0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
3       0     4        (object header)                           05 d0 ed 1f (00000101 11010000 11101101 00011111) (535678981)
4       0     4        (object header)                           05 d0 ed 1f (00000101 11010000 11101101 00011111) (535678981)

 2)線程t2打印結果為:前19次為偏向鎖膨脹為輕量鎖,從第20次開始為鎖重偏向為線程t2

    

線程名稱 線程t2  執行的次數 18
      0     4        (object header)                           05 d0 ed 1f (00000101 11010000 11101101 00011111) (535678981)
      0     4        (object header)                           10 f4 6e 20 (00010000 11110100 01101110 00100000) (544142352)
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)

 

  

線程名稱 線程t2  執行的次數 19
      0     4        (object header)                           05 d0 ed 1f (00000101 11010000 11101101 00011111) (535678981)
      0     4        (object header)                           05 e1 ed 1f (00000101 11100001 11101101 00011111) (535683333)
      0     4        (object header)                           05 e1 ed 1f (00000101 11100001 11101101 00011111) (535683333)

 

 3)從偏向鎖撤銷40次開始,鎖變為輕量級鎖
  
= 主線程新====================
新對象鎖標識:      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
新對象鎖標識:      0     4        (object header)                           a0 f5 33 03 (10100000 11110101 00110011 00000011) (53736864)

 

 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM