synchronized原理

在多线程并发编程中synchronized一直是元老级角色,很多人称之为重量级锁。而后在Java SE 1.6后对synchronized进行了优化,有的时候它就没有那么重了,引入了偏向锁和轻量级锁。

 

锁的释放和获取的内存语义

  • 当线程释放锁时,JMM会把线程对应的本地内存中的共享变量刷新到主内存中。
  • 当线程获取锁时,JMM会把该线程对应的本地内存置为无效。从而可以使得被监视器保护的临界区代码必须从主内存中读取共享变量。

  • 线程A释放了一个锁,实际上是线程A向接下来获取这个锁的某个线程发出了(线程A对共享变量所做出修改的)信息。
  • 线程B获取一个锁,实际上是线程B接收了之前某个线程发出的(在释放这个锁之前对共享变量所做修改的)消息。
  • 线程A释放锁,线程B随后获取这个锁,这个过程实际上是线程A通过主内存向线程B发送消息。

实现原理

重量级锁

  • JVM基于进入和退出Monitor对象来实现同步和代码块同步。代码块同步是使用monitorenter和monitorexit来实现的,而方法同步是使用另外一种方法来实现的,细节在JVM规范中没有说明。但方法同步依旧可以用这两个指令实现。
  • 当JVM执行引擎执行某一个方法时,其会从方法区中获取该方法的access_flags,检查其是否有ACC_SYNCRHONIZED标识符,若是有该标识符,则说明当前方法是同步方法,需要先获取当前对象的monitor,再来执行方法。
  • monitorenter指令插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处。JVM保证每个monitorenter都有对应的monitorexit与之配对。任何一个对象都有一个monitor与之关联,当一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor所有权,即尝试获取对象的锁。若获取失败,那么线程将会进入同步队列(SynchronizedQueue),在正在占有monitor的线程离开监视器后,将会通知在同步队列中的线程获取锁。
  • 优点:线程竞争不使用自旋,不会消耗CPU。
  • 缺点:线程阻塞,通过唤醒的方式来提醒其他线程,响应速度缓慢。

偏向锁

 

  • 大多情况下,锁不仅不存在多线程竞争,而且总是由同一个线程获得。那么为了获取锁和是释放锁而频繁地进行CAS操作将会显得浪费资源。

  • 偏向锁在对象头中可以储存线程的ID,以后在进入后退出同步块的时候就只需要比对对象头中的Mark Word中是否储存着当前线程的偏向锁,如果测试成功,就表示线程已经获得了锁。则检测是否为偏向锁,若不是则使用CAS竞争锁;如果是偏向锁,则尝试使用CAS将对象头的偏向锁指向当前线程。

  • 偏向锁的撤销

    • 偏向锁在遇到竞争时才会撤销
    • 撤销时,它会先暂停持有锁的线程,然后检测线程是否处于活动状态。
    • 若是不处于活动状态,则将对象头设为无锁状态。前来竞争的线程获取锁,使用CAS将偏向锁ID替换为自己的。(此时依旧是偏向锁)
    • 如果线程还活着,拥有偏向锁的栈会被执行,遍历偏向对象的锁记录,栈中的锁记录和对象头的Mark Word要么重新偏向于其他线程,要么恢复到无锁或者标记对象不适合作为偏向锁,最后唤醒暂停的线程。(此时偏向锁考虑升级为轻量级锁)
  • 需要注意的是,偏向锁适用于同步块在一个时间段内只被一个线程使用的情况,用于减少获得锁和释放锁的CAS操作,属于乐观锁。若是存在竞争,由于偏向锁的撤销会发生STW操作,将会使效率大大降低。

  • 优点:加锁和解锁不需要额外的消耗,和执行非同步方法相比仅存在纳秒级的差距。

  • 缺点:如果存在锁竞争,将会带来额外的锁撤销的消耗。

轻量级锁

  • 加锁:线程在执行同步块之前,JVM会在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。线程尝试使用CAS将对象头中的MarkWord替换为指向锁记录的指针。如果成功,当前线程获得锁。如果失败,表示其他线程竞争锁,当前线程尝试使用自旋来获取锁。

  • 解锁:使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。一旦膨胀为重量级锁,将不再恢复到轻量级锁状态。锁膨胀后,持有锁的线程在释放锁并唤醒竞争的线程,进行新一轮的夺锁。

  • 优点:竞争的线程不会阻塞,提高程序的响应速度。

  • 缺点:始终得不到锁竞争的线程,使用自旋将会消耗CPU


注意:这三种锁的强度依次递减为重量级锁->轻量级锁->偏向锁

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值