Synchronize关键字

Java实例对象对包括三部分:对象头、对象体和对齐字节

对象头

Mark Word

        在32 JVM 虚拟机中, Mark Word Class Pointer 这两部分都是 32 位的;在 64 JVM 虚拟机中, Mark Word ClassPointer这两部分都是 64 位的。在堆内存小于32GB 的情况下, 64 位虚拟机的 UseCompressedOops 选项是默认开启的,该选项表示开启 Oop 对象的 指针压缩会将原来64 位的 Oop 对象指针压缩为 32 位。 (-XX:+UseCompressedOops)。

 

偏向锁(101)

        1.在jvm没有偏向延迟的情况下,对象进行第一次加锁时理论上会去执行偏向锁的加锁流程,首先会去判断当前线程和markwords中存放是线程id是否是同一个线程。如果是则证明加锁成功,执行下面的代码。如果不是则判断偏向标识0表示不可偏向,1表示可偏向,如果判断偏向标识是1,就会用cas去改变markwords中的线程id,能改变成功则获取到锁。如果判断是不可偏向的锁就会膨胀。

        2.而能否偏向取决于有没有的调用object.hashcode和system.itdentityHashCode()方法计算哈希码,一旦对象生成了哈希码,那么就会存放到markwords中,此时偏向标识为0,表示不可偏向,因为计算了哈希码了之后该对象头无法存放线程id了。

        3.但是如果对象调用的是重写了hashcode方法,那么哈希码也不会存放到markwords中。

        4.如果一个对象正处于偏向锁状态,并且需要计算去hashcode值的话,那么偏向锁就会被撤销并且锁会膨胀

缺点

如果锁对象时常被多个线程竞争,偏向锁就是多余的,并且其撤销的过程会带来一些 性能开销。
偏向锁延迟: JVM 在启动的时候会延迟启用偏向锁机制,默认把偏向锁延迟了 4000 毫秒,因为 JVM 在 启动的时候需要加载资源,这些对象加上偏向锁没有任何意义,不启用偏向锁能减少大量偏向锁撤销

轻量锁(00)

        当线程a持有了偏向锁,这时线程b在开执行,这时会对比markwords中的线程id是否是b,这里很显然不是,那么拿锁失败后,证明这里有线程竞争。这时会执行偏向锁的撤销流程。

        持有偏向锁的线程a执行到安全点之后暂停该线程,这时会检查该线程状态,如果该线程活动已经结束或者已经退出同步代码块,则设置成无锁状态,重新执行偏向锁的流程。如果没有退出同步代码块,则升级为轻量锁,为原持有偏向锁的线程在栈上分配锁记录,拷贝对象头中markwords到原有偏向锁的锁记录中,原持有偏向锁的线程获取轻量锁,markworkds中存放指向栈中锁记录的指针。而线程b也是一样在当前栈中分配锁记录,拷贝记录,然后进行cas的加锁流程,如果加锁成功则执行同步块中代码,加锁失败则自旋再次加锁,当到达一定次数后还没有获取到锁就会升级成重量锁,防止cpu空转。

1. 普通自旋锁
有线程来竞争锁时,抢锁线程会在自旋等待,自旋的次数为 10 次,可通过 -XX:PreBlockSpin
项进行修改。
2. 自适应自旋锁
等待线程空循环的自旋次数并非是固定的,而是会动态地根据实际情况来改变自旋等待的次
数,如果抢锁线程在同一个锁对象上之前成功获得过锁,JVM 就会认为这次自旋很有可能再次
成功,因此允许自旋等待持续相对更长的时间 如果对于某个锁,抢锁线程很少成功获得过,那么JVM 将可能减少自旋时间甚至省略自旋 过程,以避免浪费处理器资源。

重量锁(10)

        当一个线程获取到锁之后,其余线程全部都处于阻塞状态。是通过对象内部的monitor (监视器)来实现的,而这个操作线程需要从用户态切换到内核态,切换成本很高。monitor (监视器)中维护着两个队列entrylist和waitset,entrylist记录着锁竞争没有获取到锁的线程,waitset中记录着调用wait()方法而阻塞的线程。线程被notify()方法唤醒后进入entrylist中排队。

锁优化

锁消除

 jvm对锁优化的一种,对运行时对上下文进行扫描,去除不可能存在资源竞争的锁。比如说给一个方法里的对象加锁,在运行时会把锁消除,因为方法里的局部变量是栈私有的,因此该对象不可能是共享资源,所以jvm会消除该对象内部的锁

锁粗化

原则上,我们使用同步锁,同步块的范围尽可能控制的越小越好,比如stringbuffer,他本身是线程安全的,因为他的关键方法被synchronize修饰过,而如果在一个循环里对stringbuffer对象重复使用append方法,那么就会出现重复对这个对象加锁,也会很损耗性能的。这是jvm就会把锁粗化到循环体的外面,避免重复加锁,使用这段操作只需要加一次锁

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值