Synchronized锁详解

文章详细阐述了Java中的SYN锁,包括锁的三种形态:偏向锁、轻量级锁和重量级锁。在JDK1.6以前,SYN锁是重量级的,通过内核态和用户态切换实现线程互斥,性能较低。后来引入了偏向锁和轻量级锁以提高效率。偏向锁通过线程ID判断加锁,轻量级锁利用栈帧和对象头的交互实现。当锁升级到重量级锁时,会涉及ObjectMonitor对象和monitorenter/monitorexit指令。
摘要由CSDN通过智能技术生成

SYN锁

public class TestDemo{
    //ClassLayOut.parseInstance(model).toPrintabl()
    //上面的代码可以拿取看model有什么

    static LockModel=new LockModel();

    public static void main (String[] args){
        lockTest();
    }
    private static viod lockTest(){
        System.out.print("hello syn");
        synchronized(model){
            //1.syn 加锁锁了说明--->锁对象
            //2. aqs:queue(队列)+cas(拿锁方式)+state(锁的状态,0未使用,可以拿)
            System。out。println("aaa");
        }
    }
}

锁头

object header
布局,类型,GC状态,同步状态,hashcode
1.mark word
1.1GC状态,同步状态(锁信息),hashcode

2.klass pointer
     实际上时只想方法区里class的字节码对象 布局
     默认指针压缩 32bit--->4byte

大小端存储.PNG

大端存储,是将数据的低位字节放到高地址处,高位字节放到低地址处。
小端存储,是将数据的低位字节放到低地址处,高位字节放到高地址处。
大端存储和小端存储记忆时,可以理解为将低位字节放到大端还是小端?大端存储就是将低为放到高地址,小端就是将低位放到低地址,这样方便记忆

计算完hashCode后,会把hashCode放入到 对象头的mark-word里面

1.3这个syn锁是怎么回事?

在jkd1.6以前,syn是一个重量级锁,它的性能很低,实际加锁的过程就是要实现线程的互斥,java没有办法直接实现,mutex函数可以实现用户态和内核态的切换,通过这样的一个切换,通过这样一个切换才能实现线程的互斥。
这样的切换(内核态和用户态)很消耗性能

就算只有一个线程,性能也会变低。

用户态内核态切换.PNG
锁的分类.PNG

锁的结构

1.4为什么有升级的这个事?

1.偏向锁:线程要尝试去加锁,会判断当前mark-word里面是否包含线程id,如果没有该线程did,线程锁会利用cas把自己的线程id写入到mark-word中,第二次这个线程再过来的时候,会判断当前中国mark-word里面是否包含该线程的id,如果有了的话,会把自己的线程id与对象头里面的线程id进行比较如果发现是一样的,此时就标识该线程获得到锁。
在这里插入图片描述

第一次加锁
在这里插入图片描述

如果在你没加锁的情况打印对象头:他默认是 无锁可以偏向
如果没加锁的情况计算了hashCode码,就是无所不可偏向(hashcode会占用mark-word)
如果在此时再加锁,无法成为偏向锁,会直接膨胀为一个轻量锁。

轻量级锁

升级到轻量级锁的三个条件:
1.现在的锁不可偏向,此时加锁随膨胀为轻量级锁
2.没有关闭延迟偏向锁,自动成为轻量级锁
3.如果查询交替出现执行情况,他会成为以一把轻量级锁

轻量锁的原理与细节:

在这里插入图片描述

1.首先方法压栈,此时中国方法栈帧压栈,栈帧就创建两个和锁有关的空间。
a》displace hrd
b》owner
2.他会将锁里面的mark-word里面的信息拷贝到hrd中
3.轻量锁会用栈帧owner指针指向对象头
4.对象头中轻量锁的指针指向当前船舰出来的中国栈帧
5.锁会修改当前的状态修改为00;
如果完成上述事务,此时才能表示加锁成功,这把锁属于当前线程;

重量级锁

java如果发现要创建一把重量级锁,java会为了我们创建一个C++的ObjectMonitor, 会让对象头中的monitor指向我们这个objectMonitor对象
如果进入到这个锁的内部,这个objectMonitor会发起汇编指定 monitorenter,当出现syn代码块时,会发出monitorexit指令如果你在syn过程中出现异常,实际上还是会执行monitorexit指令

在这里插入图片描述

对象头联盟monitor指针会执行objectMonitor对象,当对各线程加锁他的时候,会执行monitorenter指令,进入objectMonitor的entryList中等待抢锁。他们会利用cas,来进行抢锁,如果抢锁成功,objectmonitor,会把内部的owner的指针取执行抢锁成功的线程,计数器+1,如果此时抢锁的线程是持有锁的线程,那么count会再次+1,释放锁的时候count--,直到count==0九八owner置null,如果调用线程的wait方法,此时按这些被wait的线程会静茹到waitset中,只有当你取调用notifyall方法时,才会重新开始这套流程。

如果是同步方法,那么执行的指令acc——synchronized,为隐式调用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值