前言

上一章节带着大家理解了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底层原理