关于synchronized:深入JVM内置锁-synchronized-底层

45次阅读

共计 2236 个字符,预计需要花费 6 分钟才能阅读完成。

前言

上一章节带着大家理解了 Java 对象头的组成, 本节带着大家理解 synchronized 关键字的底层原理以及锁的降级过程


synchronized 原理详解

synchronized内置锁是一种对象锁 (锁的是对象而非援用),作用粒度是 对象 ,能够用来实现对临界资源的同步互斥拜访,是 可重入

什么是 Monitor

在 Java 虚拟机(HotSpot)中,Monitor 是由 ObjectMonitor 实现的。Synchronized的对象锁,MarkWord 锁标识位为 10,其中指针指向的是 Monitor 对象的起始地址。其次要数据结构如下

ObjectMonitor() {
    _header       = NULL;
    _count        = 0; // 记录个数
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;
    _WaitSet      = NULL; // 处于 wait 状态的线程,会被退出到_WaitSet
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ; // 处于期待锁 block 状态的线程,会被退出到该列表
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
  }

ObjectMonitor 中有两个队列,_WaitSet 和 _EntryList,用来保留 ObjectWaiter 对象列表(每个期待锁的线程都会被封装成 ObjectWaiter 对象),_owner 指向持有 ObjectMonitor 对象的线程,当多个线程同时拜访一段同步代码时:

  1. 首先会进入 _EntryList 汇合,当线程获取到对象的 monitor 后,进入 _Owner 区域并把 monitor 中的 owner 变量设置为以后线程,同时 monitor 中的计数器 count 加 1;
  2. 若线程调用 wait() 办法,将开释以后持有的 monitor,owner 变量复原为 null,count 自减 1,同时该线程进入 WaitSet 汇合中期待被唤醒;
  3. 若以后线程执行结束,也将开释 monitor(锁)并复位 count 的值,以便其余线程进入获取 monitor(锁);

synchronized 底层原理

synchronized 是基于 JVM 内置锁 实现,通过外部对象 Monitor(监视器锁)实现,基于进入与退出 Monitor 对象实现办法与代码块同步,监视器锁的实现依赖底层操作系统的 Mutex lock(互斥锁)实现。JVM 内置锁在 1.5 之后版本做了重大的优化,如锁粗化(Lock Coarsening)、锁打消(Lock Elimination)、轻量级锁(Lightweight Locking)、偏差锁(Biased Locking)、适应性自旋(Adaptive Spinning)等技术来缩小锁操作的开销。
每个同步对象都有一个本人的 Monitor(监视器锁):

synchronized 锁的降级过程

public class Test04 {private static Object objectLock = new Object();

    public static void main(String[] args) throws InterruptedException {
        //-XX:BiasedLockingStartupDelay=0 强制开启
//        System.out.println(">>---------------- 无锁状态 001-------------------<<");
        System.out.println(ClassLayout.parseInstance(objectLock).toPrintable());
        System.out.println("开启了偏差锁,然而偏差锁没有关联偏差锁线程");
        synchronized(objectLock){
            // 偏差锁 关联偏差锁线程
             System.out.println("开启了偏差锁,偏差是给咱们的主线程");
             System.out.println(ClassLayout.parseInstance(objectLock).toPrintable());
        }
        // 撤销偏差锁 是另外一个线程与偏差锁线程竞争
        new Thread(new Runnable() {
            @Override
            public void run() {synchronized (objectLock) {
                    try {System.out.println(ClassLayout.parseInstance(objectLock).toPrintable());
                        Thread.sleep(5000);
                        System.out.println("子线程:降级为轻量级锁");
                    } catch (Exception e) {}}
            }
        }, "子线程 1").start();
        Thread.sleep(1000);
        sync();}

    public static void sync() throws InterruptedException {System.out.println("主线程获取锁 分量级别锁");
        //11010000 01000000
        synchronized (objectLock) {System.out.println(ClassLayout.parseInstance(objectLock).toPrintable());
        }
    }

}

总结

本文次要介绍了 synchronized 底层原理

正文完
 0