synchronized锁升级的原因

历史问题

一开始的synchronized执行需要暂停线程,一旦暂停线程就需要操作系统的介入,由用户态转换为内核态,需要消耗大量的CPU资源

有时候切换的时间可能会比代码执行的时间还要长

所以我们引入轻量级锁

Monitor

每个对象都存在着一个 Monitor对象与之关联。执行 monitorenter 指令就是线程试图去获取 Monitor 的所有权,抢到了就是成功获取锁了;执行 monitorexit 指令则是释放了Monitor的所有权。

每个对象都有一个Monitor,monitor的本质是依赖于操作系统的Mutex Lock的实现,这个就是重量级锁

1. 如果一个java对象被某个线程锁住,则对象的MarkWord字段中会存在一个指向monitor地址的指针

2. Monitor的owner字段会存放拥有对象锁的线程id

偏向锁:单线程竞争

相当于经常占有资源的线程,就把这个资源直接不设置锁,让这个资源被这个线程独占,不需要引入操作系统,降低线程切换提高系统性能

偏向锁偏向于第一个访问锁的线程,将第一个线程id存储在markword里面,以后线程每次使用资源就会检查一下Markword看看里面存的是不是自己,如果是自己就不需要强锁了,直到遇到线程竞争才会释放锁

        锁竞争会尝试使用CAS的方法修改markword的id

        竞争成功,还是偏向锁,线程id变为新线程id

        竞争失败,这个时候可能会升级为轻量级锁

如果在接下来的运行过程中,该锁没有被其他的线程访问,则持有偏向锁的线程将永远不需要触发同步。也即偏向锁在资源没有竞争情况下消除了同步语句,懒得练CAS操作都不做了,直接提高程序性能

性能最高

轻量级锁

本质是CAS

JVM会为每个线程在当前线程的栈帧中创建用于存储锁记录的空间,官方成为Displaced Mark Word。若一个线程获得锁时发现是轻量级锁,会把锁的MakWord复制到自己的Displaced Mark Wod里面。然后线程尝试用CAS将锁的MarkWord替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示Mark Word已经被替换成了其他线程的锁记录,说明在与其它线程竞争锁,当前线程就尝试使用自旋来获取锁。

重量级锁

当轻量级锁自旋的次数超过一定次数,就进行锁升级为重量级锁

基于monitor实现了

在编译时加入monitor enter和monitor exit

当线程执行到monitor enter指令时,会尝试获取对象所对应的Monitor所有权,如果获取到了,即获取到了锁,会在Monitor的owner中存放当前线程的id,这样它将处于锁定状态,除非退出同步块,否则其他线程无法获取到这个Monitor。

锁升级为轻量锁或者重量锁之后mark word保存的是两个锁的指针,已经没有位置保存hash码了,那么hash码在哪里?

hash码在称为偏向锁的时候就没有了,但是升级为重量锁的时候又有了只不过这个时候的hash码存储在objectmonitor里面

一个对象调用hashcode之后就没办法称为偏向锁了,如果还要上锁的话就直接变为轻量级锁

小结

JIT编译器与锁

锁消除

当对象称为锁,然后再进行hashcode方法,就会让这个锁变成无锁

再jit层面,相当于sychronized不存在

锁粗化

public class LockBigDemo
{
    static Object objectLock = new Object();

    public static void main(String[] args)
    {
        new Thread(() -> {
            synchronized (objectLock){
                System.out.println("111111");
            }
            synchronized (objectLock){
                System.out.println("222222");
            }
            synchronized (objectLock){
                System.out.println("333333");
            }
            synchronized (objectLock){
                System.out.println("444444");
            }

            synchronized (objectLock){
                System.out.println("111111");
                System.out.println("222222");
                System.out.println("333333");
                System.out.println("444444");
            }

        },"t1").start();
    }
}

如果有多段sychronized锁住的代码块,再jit层面可能会进行锁合并,把它变成一个sychronized区块

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值