JDK1.5之前和之后实现方法同步的方式

在jdk1.5之前,我们想要实现线程同步,只能通过synchronized关键字这一种方式来达成,底层,JAVA也是通过synchronized关键字来做到数据的原子性的,synchronized关键字是jvm实现的一种内置锁,从底层角度来说,这种锁得获取和释放是由jvm帮助我们隐式实现的

从jdk1.5开始,并发包引入了lock锁,lock同步锁是基于JAVA来实现的,因此锁的获取和释放都是通过JAVA代码来实现和控制的,然而synchronized是基于底层操作系统Mutex lock来实现的,每次对锁的获取和释放都会带来用户态和内核态之间的切换,这种切换会极大的增加系统的负担。在并发量较高时,也就是说锁的竞争比较激烈时,synchronized锁在性能上的表现就非常差

从jdk1.6开始。synchronized锁的实现发生了很大的变化,jvm引入了相应的优化手段来提升synchronized锁的性能。这种提升涉及偏向锁。轻量级锁。重量级锁等,从而减少锁的竞争所带来的用户态和内核态之间的切换,这种锁的优化实际上是通过JAVA对象头中的一些标志位来去实现的,对于锁的访问和改变。实际上都和JAVA对象头息息相关
对象头主要也是由三个内容构成:
1,Mark Word
2,指向类的指针
3,数组长度

其中Mark Word,(它记录了对象,锁。及垃圾回收相关的信息,在64位的jvm中,其长度也是64bit)的位信息包括了如下组成部分:
1,无锁标记
2,偏向锁标记
3,轻量级锁标记
4,重量级锁标记
5,GC标记

对于synchronized锁来说,锁的升级主要都是通过Mark Word中的锁标志位与是否是偏向锁标志位来达成的,synchronized关键字所对应的锁都是先从偏向锁开始,随着锁竞争的不断升级,逐步演化至轻量级锁,最后变成了重量级锁

对于锁的演化来说,它会经历如下阶段:
无锁>偏向锁>轻量级锁>重量级锁

偏向锁:
针对于一个线程来说的,它的主要作用就是优化同一个线程多次获取一个锁的情况,如果一个synchronized方法被一个线程访问。那么这个方法所在的对象就会在其Mark Word中的将偏向锁进行标记。同时还会有一个字段来存储该线程的ID,当这个线程再次访问同一个synchronized方法时,它会检查这个对象的Mark Word的偏向锁标记以及是否指向了其线程ID,如果是的话。那么该线程就无需再去进入管程(Monitor)了。而是直接进入到该方法中

如果是另一个线程访问这个synchronized方法,那么偏向锁会被取消掉

轻量级锁:
若第一个线程已经获取到当前对象的锁,这时第二个线程又开始尝试争抢该对象的锁,由于已经被第一个线程获取,因此它是偏向锁。而第二个线程在争抢时,会发现该对象头中的Mark Word已经是偏向锁,但里面存储的线程ID不是自己。那么它会进行CAS(compare and swap)从而获取到锁。这里面存在两种情况:

1,获取锁成功,那么它会直接将Mark Word中的线程ID由第一个线程变成自己(偏向锁标志位保持不变)。这样该对象依然会保持偏向锁的状态

2,获取锁失败:表示这时可能会有多个线程同时在挣钱该对象的锁,那么这时偏向锁会升级,升级为轻量级锁

自旋锁:若自旋失败(依然无法获取到锁),那么锁就会转化成重量级锁。在这种情况下,无法获取到锁的线程都会进入到Monitor(即内核),自旋最大的一个特点就是避免咯线程从用户态进入到内核态

重量级锁:线程最终从用户态进入到了内核态

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值