synchronized的批量重偏向与批量撤销

synchronized的批量重偏向与批量撤销

  • 基础知识补充
    • 小端存储
    • 相关JVM参数
    • 上代码
    • 代码

基础知识补充

java对象的对象头信息分布:(64位机)

 |------------------------------------------------------------------------------|--------------------|
 |                                  Mark Word (64 bits)                         |       State        |
 |------------------------------------------------------------------------------|--------------------|
 | unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 |       Normal       |  无锁
 |------------------------------------------------------------------------------|--------------------|
 | thread:54 |       epoch:2        | unused:1 | age:4 | biased_lock:1 | lock:2 |       Biased       |  偏向锁
 |------------------------------------------------------------------------------|--------------------|
 |                       ptr_to_lock_record:62                         | lock:2 | Lightweight Locked |   轻量级
 |------------------------------------------------------------------------------|--------------------|
 |                     ptr_to_heavyweight_monitor:62                   | lock:2 | Heavyweight Locked |  重量级
 |------------------------------------------------------------------------------|--------------------|
 |                                                                     | lock:2 |    Marked for GC   |   GC标记
 |------------------------------------------------------------------------------|--------------------|

总结下即为:
 biased_lock	lock	状态
 0	            01	    无锁
 1	            01	    偏向锁
 0	            00	    轻量级锁
 0	            10	    重量级锁
 0	            11	    GC标记


小端存储

咱们使用的电脑普遍都是小端存储:高位的字节 存在内存的高地址中

使用JOL打印的对象头信息应该反着看,即:

 反读的单位是字节 也就是8位

 unused:1 | age:4 | biased_lock:1 | lock:2 |        identity_hashcode:31    0     unused:24

相关JVM参数

偏向锁默认延迟启动(延迟4s左右)

 通过JVM的参数来禁用延迟-
 XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0

打印JVM 参数: -XX:+PrintFlagsFinal

  •  intx BiasedLockingBulkRebiasThreshold          = 20                                  {product}   偏向阈值
    
  •  intx BiasedLockingBulkRevokeThreshold          = 40                                  {product}   撤销阈值
    

上代码

依赖

    
        
        
            org.openjdk.jol
            jol-core
            0.8
        
    

代码

使用:-XX:BiasedLockingStartupDelay=0 启动,开启偏向锁
代码中可以证明偏向锁的批量重偏向和批量撤销


import org.openjdk.jol.info.ClassLayout;

import java.util.ArrayList;
import java.util.List;

import static java.lang.System.out;

public class JOLExample {
    static List list = new ArrayList();
    public static void main(String[] args) throws Exception {

        Thread t1 = new Thread() {
            public void run() {

                for (int i=0;i<100;i++){
                    A a = new A();
                    synchronized (a){
                        list.add(a);
                    }
                }
                out.println(" add end --------");

                if (list.size() == 100){
                    A a = list.get(60);
                    synchronized (a){
                        try {
                            this.currentThread().sleep(1000000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }
        };
        t1.start();
        //t1.join();
        Thread.sleep(5000);


        out.println("before t2   1:" +  ClassLayout.parseInstance(list.get(1)).toPrintable());

        out.println("before t2   60:" +  ClassLayout.parseInstance(list.get(60)).toPrintable());


        Thread t2 = new Thread() {
            int k=0;
            public void run() {
                for(A a:list){
                   synchronized (a){
                      // System.out.println("22222");
                       if ( k== 18 || k==26 ){
                           //轻量锁
                           out.println("t2 ing  ------ K=" + k + "  |" + ClassLayout.parseInstance(a).toPrintable());

                           /**
                            * 当K 为 20 时, 60 的 epoch 会变为  01 原因:
                            *       当批量偏向到达阈值时,会进行如下操作:
                            *           1.会修改Class类对象的中 epoch 字段,为: 01 【没有找到是哪一个字段,无法证明】
                            *           2.会扫描该Class的所有对象:
                            *                   A:如果当前Class的对象,在同步块中,则修改 epoch 的值与 Class类对象中的 epoch 字段相等
                            *                   B:如果当前Class的对象,不在同步块中则不进行修改
                            *
                            */
                           out.println("t2 ing  ------ K=" + k + "  60:" +  ClassLayout.parseInstance(list.get(60)).toPrintable());
                       }
                   }
                   k++;
                   if (k==50){
                       out.println(" t2 end -------------------");
                       A a1 = list.get(80);
                       synchronized (a1){
                           try {
                               this.currentThread().sleep(1000000);
                           } catch (InterruptedException e) {
                               e.printStackTrace();
                           }
                       }
                   }
                }

            }
        };
        t2.start();
        //t2.join();

        Thread.sleep(5000);
        out.println("main ing  ----  80:" +  ClassLayout.parseInstance(list.get(80)).toPrintable());

        Thread t3 = new Thread() {
            int k=0;
            public void run() {
                for(A a:list){
                    k++;
                    if (k > 20){
                        synchronized (a){
                            if ( k == 26  || k == 45 ){
                                //轻量锁
                                out.println("T3 ing  ------ K=" + k + "  |" + ClassLayout.parseInstance(a).toPrintable());
                                /**
                                 * 26 偏向     45 轻量
                                 * 当T3 线程 批量撤销 偏向锁的对象 超过阈值:20 时: (问题: 批量撤销总次数阈值为 40 ,这里为什么是 20 ?  因为 T2 线程 在进行重偏向时, 已撤销了20次【前20个对象】,这里只剩下 20 次)
                                 *      会扫描对正在同步块中的对象 。对所有对象进行撤销 偏向锁 ,全部置为 轻量级锁 ,因此 当K 为 45时,已发生批量 撤销, 80 已置为 轻量级锁
                                 */
                                out.println("T3 ing  ------ K=" + k + "  80:" +  ClassLayout.parseInstance(list.get(80)).toPrintable());
                            }
                        }
                        if (k==45){
                            return;
                        }
                    }

                }

            }
        };
        t3.start();
        t3.join();
        // 轻量级锁
        out.println("main ing  ----  80:" +  ClassLayout.parseInstance(list.get(80)).toPrintable());



    }



class A {
    int i=0;
}

你可能感兴趣的:(java,jvm,sync,多线程)