Synchronized原理

synchronized特性

synchronized也叫做同步锁,解决的是多个线程之间对同一资源抢占导致的一致性问题,既同一时刻,被synchronized修饰的方法或者代码块只有一个线程在执行,其他线程必须等待,解决并发安全问题。

原子性

原子性就是指一个或多个操作,要么全部执行,要么全部不执行。换句话说,就是一个操作是不能分割,不可中断的,一个线程在执行时不会被其他线程干扰。

可见性

只要有一个线程对共享资源做了修改,那么该资源的状态,值信息对其他线程都是可见的。
volatile:也可以保证可见性,被volatile修饰的变量每当值修改时,会被立即修改进主内存。
synchronized:synchronized修饰的方法或者代码块内的变量在unlock之前必须修改进主内存。

有序性

synchronized和volatile都具有有序性。java在编译时会进行指令重排,并发执行时,重排可能会造成计算结果与预期不符。
volatile:使用内存屏障来阻止重排序,保证有序性。
synchronized:其是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”规则得出的,此规则决定了持有同一个对象锁的两个同步块只能串行进入。

可重入性

Synchronized和ReentrantLock都是可重入锁,当一个线程试图操作一个由其他线程持有的对象锁的临界资源时,将会处于阻塞阶段;但是当一个线程再次请求自己持有对象锁的临界资源时,这时候属于重入锁。

synchronized原理

synchronized是java内置锁,是通过对象头的锁状态标志和锁记录来实现的,每个java对象都有对象头,其中包含了锁状态标志位,指向锁记录的指针等信息。

Java 对象在内存中布局分为三部分:对象头、实例数据和对齐填充。对象头中包含了关于锁的信息。具体来说,对象头中有一个 Mark Word,用于存储对象的哈希码、分代年龄、锁状态等信息。
在这里插入图片描述

锁升级原理

java6之前,synchronized实现基本是基于重量级锁实现,即当线程获取锁失败时,会被阻塞并导致用户态和内核态的切换,性能开销很大。java6后,引入了无锁,偏向锁,轻量级锁,重量级锁多种锁状态,大大优化了synchronized性能。

  1. 无锁状态
    对象刚开始处于无锁状态,也没有任何线程持有该对象的锁
  2. 偏向锁
    偏向锁是为了减少无竞争情况下的锁开销,当一个线程首次访问代码块时,它会在对象头和当前线程的栈帧中记录偏向的线程ID。这样在后续执行中,如果仍然是同一个线程访问该代码块,JVM可以判断出来,并允许无锁进行操作。
    但是,当其他线程尝试获取这个偏向锁时,偏向锁就会撤销,并尝试升级为轻量级锁。
  3. 轻量级锁
    轻量级锁是为了减少阻塞而设计的,轻量级锁的加锁过程是通过CAS来实现的,它试图将 Mark Word中的锁记录指针替换成线程栈帧中锁记录的指针,如果替换成功则当前线程获取锁,如果失败,此时会尝试自旋等待。
    如果当前线程自旋一定次数仍然没有获取锁,此时会尝试升级为重量级锁。
  4. 重量级锁
    重量级锁依赖于操作系统中的互斥量(Mutex)。当轻量级锁无法满足性能需求时,会转换成重量级锁,此时,未获取锁的线程会被阻塞,进入等待,知道持有锁的线程释放锁。
    重量级锁的实现依赖于底层的 Monitor 机制。每个对象都有一个与之关联的 Monitor,当线程尝试获取重量级锁时,会被放入 Monitor 的入口等待队列中。如果获取锁失败,线程会被阻塞并放入等待队列,直到持有锁的线程释放锁。
  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值