synchronized的实现原理与应用

为什么要使用synchronized关键字呢?

这是因为多线程之间数据是共享的,他们可以同时对一个数据进行读写,这是如果两个线程同时对一个数据进行写操作时,只会有一个的数据写入成功,因此我们需要使用锁保证资源的读写安全。

synchronized是什么呢?

在多线程并发编程的过程中synchronized一直都是一个很重要的角色,很多人都称呼他为重量级锁,但是在Java SE 1.6时对它进行了优化,因此他有些时候变得不那么重了。

synchronized关键字在需要原子性、可见性和有序性这三种特性的时候都可以作为其中一种解决方案,看起来是“万能”的。的确,大部分并发控制操作都能使用synchronized来完成。

锁的使用场景:

1、对于普通同步方法,锁时当前的实例对象。

2、对于静态同步方法,锁指的是当前类的Class对象。

3、对于同步方法块,锁指的是synchronized括号里配置的对象。

那么锁的实现原理是什么呢

在JVM规范中指出,JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。代码块同步时使用monitorenter和monitorexit指令实现的,而方法同步是使用另一种方式实现的,JVM规范并没有给出详细说明,但是方法的同步同样也可以使用这两个指令实现。

monitorenter和monitorexit指令会在程序编译后插入到同步块开始和结束(和异常)的位置,而且JVM要保证monitorenter和monitorexit成对出现。任何对象都有一个monitor对象与之相关联,当一个monitor被持有后,他将会处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的minitor所有权,即尝试获取对象的锁。

锁存储在哪里呢?

synchronized用的锁时存在Java对象头里的。这里特别要注意,如果对象是数组类型,虚拟机将会用3个字字宽储对象头,而非数组类型,用2个字宽(在32虚拟机上一个字宽代表4个字节)。

比如在32位的HotSpot虚拟机中对象未被锁定的状态下,Mark Word的32bit空间中的25bit用于存储对象哈希码,4bit用于存储对象分代年龄,2bit用于存储锁标志位,1bit固定为0。
其主要的几个状态如下:

状态标志位存储内容
未锁定01对象哈希码、对象分代年龄
轻量级锁定00指向锁记录的指针
重量级锁定10指向重量级锁的指针
GC标志11空,不需要记录信息
可偏向01偏向线程ID、偏向时间戳,对象分代年龄

Java SE 1.6之后锁都有哪些变化?

1、偏向锁

HotSpot的作者经过研究发现,大多数情况下,锁不仅不存在多线程竞争,而且总由同一线程多次获得,因此为了让这个线程更容易的获取锁引入了偏向锁的概念。从偏向锁的语义中我们能听出,偏向某一线程获得锁就是她的意思。即当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储偏向的线程的ID,以后该线程在进入和退出同步块的时候不需要进行CAS操作来加锁和解锁,只需要简单的测试一下对象头里的Mark Word里时是否存储着指向当前线程的偏向锁。。如果测试失败,需要检测Mark Word里存储的偏向锁标志是否为1(表示当前为偏向锁),如果没有设置,则使用CAS竞争锁,否则尝试使用CAS将对象头的偏向指向当前线程。

(1、1)偏向锁的撤销

只有在出现锁竞争是才会释放偏向锁,撤销时需要等待全局安全点(这个时间点上没有正在执行的字节码)。它首先会暂停所有拥有偏向锁的线程,然后检查是否由线程还活着,如果没有则将对象头设置为无锁状态;如果还有线程活着,会遍历栈去将Mark Word的指向重新偏向于其他线程,或者恢复到无锁。

(1.2)关闭偏向锁

在JAVA6 和JAVA7中,偏向锁是默认开启的,但是他会在程序启动几秒后启动,这是为了确定程序中是否有线程竞争,如果有竞争,那么程序会进入轻量锁状态

如图所示:

2、轻量级锁
如果说偏向锁是只允许一个线程获得锁,那么轻量级锁就是允许多个线程获得锁,但是只允许他们顺序拿锁,不允许出现竞争,也就是拿锁失败的情况,轻量级锁的步骤如下:

1)线程1在执行同步代码块之前,JVM会先在当前线程的栈帧中创建一个空间用来存储锁记录,然后再把对象头中的Mark Word复制到该锁记录中,官方称之为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word 替换为指向锁记录的指针。如果成功,则获得锁,进入步骤3)。如果失败执行步骤2)

2)线程自旋,自旋成功则获得锁,进入步骤3)。自旋失败,则膨胀成为重量级锁,并把锁标志位变为10,线程阻塞进入步骤3

3)锁的持有线程执行同步代码,执行完CAS替换Mark Word成功释放锁,如果CAS成功则流程结束,CAS失败执行步骤4)

4)CAS执行失败说明期间有线程尝试获得锁并自旋失败,轻量级锁升级为了重量级锁,此时释放锁之后,还要唤醒等待的线程

如图所示:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值