前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入JVM内置锁 synchronized 底层

深入JVM内置锁 synchronized 底层

原创
作者头像
janyxe
发布2022-04-19 15:54:29
3770
发布2022-04-19 15:54:29
举报
文章被收录于专栏:Java从零学架构

前言

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


synchronized原理详解

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

什么是Monitor

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

代码语言:java
复制
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底层原理.png
synchronized底层原理.png

synchronized锁的升级过程

代码语言:java
复制
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锁的升级过程.jpg
synchronized锁的升级过程.jpg

总结

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • synchronized原理详解
  • 什么是Monitor
  • synchronized底层原理
  • synchronized锁的升级过程
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档