Synchronized的底层实现原理

一、Synchronized锁表现的三种形式

  1. 对于普通方法,锁的是当前的是对象
  2. 对于静态同步方法,锁的是当前类的class对象
  3. 对于同步代码块,锁的是synchronized括号里配置的对象

二、Synchronized的底层实现

1. 为什么synchronized被叫做重量级锁

synchronized是通过对内部的监视器锁(monitor)来实现的,而监视器锁又是依赖于操作系统中的互斥锁(Mutex Lock)来实现的,而操作系统实现线程之间的切换从用户态转换为内核态,这个成本会非常的高,转换需要的时间需要相对比较长的时间,这也是为什么synchronized效率低的原因,所有底层依赖于Mutex Lock 实现的锁,我们称之为重量级锁

synchronized的底层实现是完全依赖JVM虚拟机的,所以谈synchronized的底层实现,就不得不谈数据在JVM内存的存储:Java对象头,以及Monitor对象监视器。

2.对象在内存存储中的存储布局

在这里插入图片描述

  1. 类型指针(class Pointer)
    是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

  2. 标记字段(Mark Word)
    用于存储对象自身的运行时数据,如哈希码(HashCode)、GC信息、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等,它是实现轻量级锁和偏向锁的关键。

  3. 实例数据(instance data):记录了对象里面的变量数据。

  4. 对齐填充 (padding):作为对齐使用,对象在64位服务版本中,规定对象内存必须要能被8字节整除,如果不能整除,那么久靠对齐来不。举个例子:new出了一个对象,内存只占用18字节,但是规定要能被8整除,所以padding=6

  5. Monitor
    monitor描述为对象监视器,可以类比为一个特殊的房间,这个房间中有一些被保护的数据,monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据,进入房间即为持有monitor,退出房间即为释放monitor。

3. synchronized 的锁升级

锁解决了数据的安全性,但是同样带来了性能的下降,hotspot 虚拟机的作者经过调查发现,大部分情况下,加锁的代码不仅仅不存在多线程竞争,而且总是由同一个线程多次获得。

所以基于这样一个概率,synchronized 在JDK1.6 之后做了一些优化,为了减少获得锁和释放锁来的性能开销,引入了偏向锁、轻量级锁,锁的状态根据竞争激烈的程度从低到高不断升级。

1.无锁

无锁没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。

2.偏向锁

偏向锁是JDK6中引入的一项锁优化,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

偏向锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。

3.轻量级锁

是指当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。

4.重量级锁

指的是原始的Synchronized的实现,重量级锁的特点:其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程。

简单描述:

  1. 没有线程访问时,处于无锁状态
  2. 当有一个线程访问时,则转为偏向锁
  3. 当有第二个锁来访问时,转为轻量锁
  4. 轻量级锁以自旋的方式获取锁,当自旋的次数达到阈值时(默认为10次),则升级为重量级锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值