Synchronized锁升级过程

new出来对象在堆内存中的内存布局

  1. markword 8个字节 (synchronized主要影响的是markword)markword记录了锁信息,gc信息,hashcode
  2. klass pointer 指向类.class 即表示对象属于哪个class的对象 默认4个字节
  3. 成员变量,比如int m=8;int类型的变量占据4个字节
  4. padding对齐

64位的虚拟机,对齐是8个字节,之所以是8个字节是指整体这个对象所占用字节总和必须能被8整除

JOL=Java Object Layout工具的使用

jol是对象内存布局查看工具

引入

        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>

案例

情况一:下面我们用jol解析new出来的对象o的内存布局

public class JolTest {
    public static void main(String[] args) {
        Object o=new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}

执行结果:

从第0个位置往后数4个字节和从第4个位置往后数4个字节总共8个字节这两部分加起来8个字节是markword,从第8个字节开始往后数4个是klass pointer,从第12个字节开始加4个字节对齐组成16个字节

情况二:下面我们对对象o加一把锁,然后来再看它的内存布局变化

public class JolTest {
    public static void main(String[] args) {
        Object o=new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());

        synchronized (o){
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
}

执行结果:

可以看到锁定对象前对象的markword和锁定对象后对象的markword不一样了,因此我们可以认识到,锁定对象后对象的markword中一定有锁信息

每个组的第一行的括号后面的第一个8位的最后3位可以看锁信息,不如上面是001(无锁态),下面是000(自旋锁)

左边是右边二进制位的十六进制表示形式,比如C8的二进制表示为11001000

总结

markword记录了锁信息,gc信息,hashcode

Synchronized锁升级过程

Synchronized锁在jdk1.2之前效率非常低,后面逐步优化,在jdk1.6以后优化到了一个比较好的状态,这个状态就是Synchronized锁升级过程

用户态和内核态

windows或者linux操作系统都有一个内核,称为kernel。最早的时候,kernel和我们的应用程序不区分,这就导致应用程序直接访问硬件(内存,网卡,显示器),很容易把硬件搞坏,比如直接把操作系统用的内存干掉,导致操作系统down

鉴于此,现在的操作系统一般分为两层,kernel工作的是内核态,我们自己的应用程序工作的时候是用户态。这样,如果用户态的程序要访问内存必须先经过内核态的允许,从用户态转到内核态,拿到结果以后再将数据从内核态转移到用户态

JVM相对于操作系统来说也就是一个普通程序。

JDK早期,Synchronized叫做重量级锁,因为申请锁必须通过内核kernel,系统调用才能拿到这把锁。之所以说是重就是因为需要经过操作系统内核的帮助,因此这是一个效率很低的耗时操作,即使线程很少的情况下

后面对锁逐步优化,就是某些情况下不再需要经过内核,直接在用户空间就可以解决,比如CAS,是轻量级锁

Synchronized锁升级过程

如果最后2位是0,1,则偏向锁和无锁态相同因此无法区分,所以再加一位,因此第三位叫偏向锁位

无锁态-> 偏向锁 ->轻量级锁(又称自旋锁/无锁(之所以叫原因是没有内核状态的锁即CAS))

偏向锁和自旋锁都是在用户空间完成的
重量级锁是需要向内核申请

偏向锁和偏向锁的升级

偏向锁默认是启动的,但是会延迟,JVM启动以后,4秒以后偏向锁才会起作用

就是偏向你一个人,偏向锁实际上就是没有锁,将自己的id贴上去即可,之所以会有偏向锁,因为本来很多时间就是只有一个线程在运行,但这个方法天生就加了一个synchronized,如果向内核申请一个重量级锁效率太低了。
比如我们业务白天访问量很大,存在并发访问情况,可能晚上就一个人访问或者没有,如果我们直接加个重量级锁很明显效率很低。

因此我们直接只是单纯加一个标记,比如张三要上厕所,他在门上贴一张条张三,然后就进去。如果这时候有其他两个线程也来抢这个资源的话,那么就要出现锁竞争,让张三暂停,然后将张三加的偏向锁的标记撤下来,即锁撤销(将张三的纸条撕下来),开始上自旋锁。因为偏向锁并未加锁,只是贴了个标记,不存在锁释放概念:张三醒过来,继续开始执行。其他线程等张三执行完后(之所以要等是因为如果其他线程抢占到了锁,那么张三这次操作就不具备原子性,是线程不安全的)释放锁后,谁能将自己的lock Record贴到门上去,谁就抢到了这把锁。当竞争越来越激烈的时候,才会升级为重量级锁

分析jvm源码(biasedLocking.cpp)解析的偏向锁升级流程,示例中:线程1当前拥有偏向锁对象,线程2是需要竞争到偏向锁。

线程2来竞争锁对象:
判断当前对象头是否是偏向锁;
判断拥有偏向锁的线程1是否还存在;
线程1不存在,直接设置偏向锁标识为0(线程1执行完毕后,不会主动去释放偏向锁);
使用cas替换偏向锁线程ID为线程2,锁不升级,仍为偏向锁;
线程1仍然存在,暂停线程1;
设置锁标志位为00(变为轻量级锁),偏向锁为0;
从线程1的空闲monitor record中读取一条,放至线程1的当前monitor record中;
更新mark word,将mark word指向线程1中monitor record的指针;
继续执行线程1的代码;
锁升级为轻量级锁;
线程2自旋来获取锁对象;

偏向锁升级轻量级锁条件:只要再来一个线程竞争就升级
偏向锁和自旋锁的区别:自旋锁是需要耗费cpu资源的

有了轻量级锁,为什么还要升级重量级锁

轻量级锁适合锁定以后执行时间较短的场景,或者线程数较少的场景。和重量级锁最重要的区别就是自旋锁是需要占用cpu资源的,因为自旋就要循环,而重量级锁是不需要消耗cpu资源的,原因是重量级锁下面有两个队列,一个竞争队列,一个等待队列。比如之前可能有100个线程在自旋消耗cpu资源,现在不需要再自旋,将其扔到一个等待队列waitSet中等着即可,什么时候轮到这个线程,操作系统将其叫醒然后执行,轮不到那个线程的时候,他就等着即可,属于阻塞

轻量级锁升级重量级锁条件:自旋超过10次,升级为重量级锁,原因:如果太多线程自旋CPU消耗过大,不然升级为重量级锁,进入等待队列(不消耗cpu)

总结

new一个对象,加锁的时候,先加上偏向锁,有轻度竞争的时候升级为轻量级锁,轻量级锁有重度竞争的话升级重量级锁(锁膨胀)。
如果有耗时过长的操作或者wait'操作,偏向锁会直接升级重量级锁

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354