首页 > 其他分享 >决战圣地玛丽乔亚Day33 ---Synchronized && volatile

决战圣地玛丽乔亚Day33 ---Synchronized && volatile

时间:2023-03-15 09:11:06浏览次数:31  
标签:加锁 乔亚 Synchronized 对象 Day33 线程 轻量级 偏向

再Synchronized和ReetrantLock的区别:

1.Synchronized可以对静态方法,普通方法,代码块加锁。自动加锁释放锁。
ReetrantLock需要手动的加锁释放锁,加锁前需要创建一个ReetrantLock对象
2.Synchronized是非公平锁,竞争获取。ReetrantLock可以使用非公平锁和公平锁两种模式。
3.synchronized 是 JVM 层面通过监视器monitor实现的,而 ReentrantLock 是基于 AQS 实现的
4.Synchronized会有死锁的情况,不能中断。ReetrantLock可以响应中断lockInterruptibly

 

锁升级的过程:

jdk6之前,只有无锁和重量级锁。jdk6后引入了偏向锁和轻量级锁。

synchronized通过操作系统切换CPU状态来阻塞和唤醒线程,效率低下。所以引入偏向锁和轻量级锁。

首先要明白Synchronized加锁是对什么数据进行操作。

一个对象创建出来后,在内存中的布局大致是:

8字节的Markword

4字节的classPoin(对象引用,指向对象内存地址的变量)

实例数据

字节填充(例如8字节对其的JVM,需要填充一些字节进行对齐)

 

对于markword:

 

 

 synchronized对对象加锁,主要改的就是markword数据。

 

1.升级的过程

无锁--->偏向锁
刚开始,无锁状态,对象没有被任何线程持有过锁,此时的标记位是01(是否偏向锁的标记是0),可以被任意线程持有锁。如果有线程此时获取了锁,是否偏向锁变为1,锁标志位还是01.

变为偏向锁的同时,线程栈中创建一个锁记录(LockRecord)并且会把markword拷贝到LockRecord中,LR中记录锁id和时间戳。同时被加锁对象的markword中的指针也会指向当前持有偏向锁线程的LockRecord。

当其他线程尝试获取对象锁,会去看LR的持有锁的id,如果相同就直接重入。

注意:LR是只有在偏向锁竞争的情况下才会产生,也就是偏向锁失效的情况下,才会用LR记录新的竞争者的信息。所以如果存在LR的偏向锁对象,这时候已经是轻量级锁的状态。

偏向锁是不会主动释放的,只有遇到了其他线程竞争偏向锁时才会主动释放掉偏向锁。

关于偏向锁的撤销:

偏向锁的 撤销(revoke)是一个很特殊的操作,为了执行撤销操作,需要等待全局安全点,此时所有的工作线程都停止了执行。偏向锁的撤销操作并不是将对象恢复到无锁可偏向的状态,而是在偏向锁的获取过程中,发现竞争并且对方并没有结束释放偏向锁时,直接将一个被偏向的对象升级到被加了轻量级锁的状态。
由于偏向锁的移除需要在全局安全点的时候执行,所以如果当有大量线程竞争同一个锁资源时,我们可以通过关闭偏向锁来调优系统性能。

需要等到全局安全点(没有字节码在执行),会先暂停偏向锁线程,然后判断锁的对象是否被锁定。如果线程不处于活跃状态,对象头设置为无锁,并撤销偏向锁,改为无锁或轻量级锁。  

 

 

add:匿名偏向

把偏向锁的延迟设置为0,-XX:BiasedLockingStartupDelay=0

 

 

 锁是偏向锁,但是没有记录占有这个偏向锁的线程的指针。这种情况就是匿名偏向。

 

 


偏向锁--->轻量级锁
当处于偏向锁的状态下,如果有其他线程来竞争改对象的锁,首先撤销偏向锁升级为轻量级锁。然后线程A、B通过CAS自旋来获取锁,获取锁成功的线程记录LR,改标记位00;没有获取到锁的线程就自旋,超过一定次数的自旋后,会升级为重量级锁。 

当没有处在偏向锁的状态下,线程之间直接通过CAS+自旋的方式进行竞争。

 

轻量级锁--->重量级锁

JVM是运行在用户态的,而要对一个对象上锁就要去内核态的OS申请锁,然后把这把锁返回到用户态。这个用户态到内核态对性能有一定的消耗。

抢占到重量级锁后,markdown里面记录的不再是LR的指针,而指向对象ObjectMonitor。

Monitor的本质是一个同步机制,保证同时只有一个线程能够进入临界区

Monitor:

  -ContentionQueue:所有竞争锁的线程都会先到这个队列中阻塞。

  -WaitSet等待队列,Owner线程被阻塞后,会加入等待队列,唤醒后加入EntryList

  -EntryList阻塞队列,经过初次ContentionQueue筛选的的线程进入。

  -Owner 拥有当前Monitor对象的线程

  -Count 可重入锁的实现

对于没有抢占到重量级锁的线程,会被存入阻塞队列EntryList,持有重量级锁的线程执行完任务后,会唤醒EntryList的线程去抢占锁。

 

偏向锁的好处:

如果没有其他线程竞争,那么每次拿锁就是重入,降低了获取锁的代价。但是如果并发高,使用偏向锁还不如不用。

轻量级锁的好处:

通过多次的自旋尝试去获取锁,如果在可接受次数内拿到了锁,就不需要去进行用户态到内核态的切换。但是自旋也占用很多CPU资源,所以需要一个可接受范围的自旋次数。

轻量级锁比直接无脑用重量级锁要好一些。

重量级锁:

如果自旋次数过多,那么可能还不如通过用户态到内核态状态的切换去拿锁资源消耗的少,这种情况下重量级锁更合适一些。

标签:加锁,乔亚,Synchronized,对象,Day33,线程,轻量级,偏向
From: https://www.cnblogs.com/dwj-ngu/p/17215536.html

相关文章

  • Synchronized锁升级过程
    Synchronized痛点JDK1.6以前Synchronized锁是一个非常重的锁,虽然确实保证了并发的安全性,但是却也导致了性能的大幅降低;为了解决这个问题,JDK1.6开始出现了锁升级机制,根据具......
  • 决战圣地玛丽乔亚Day
    今日目标(AQS):AQS(抽象队列同步器):相当于实现锁的一系列模板方法。如果要实现锁,需要:1.锁是否被占用的状态值。2.阻塞/唤醒3.竞争失败的队列AQS中:state:状态信息,不同......
  • Lock锁(性能更好,是代码块锁,synchronized锁能锁方法)
    packagecom.Java;importjava.util.concurrent.locks.ReentrantLock;//可重入锁publicclassTestLock{publicstaticvoidmain(String[]args){TestLock2......
  • synchronized保证线程安全
    packagecom.Java;//银行不安全案例两个人同时取钱//使用synchronized和synchronized块可以锁住对象保证线程的安全性publicclassTestBank{publicstaticvoid......
  • synchronized与CAS
    synchronizedsynchronized是⼀种互斥锁,⼀次只能允许⼀个线程进⼊被锁住的代码块synchronized是Java的⼀个关键字,它能够将代码块/⽅法锁起来如果synchronized修饰的是实例......
  • 决战圣地玛丽乔亚Day25-----慢查询优化和索引优化
    建索引的几大原则1.最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a=1andb=2andc>3andd=4如果......
  • 决战圣地玛丽乔亚Day24
    高性能Mysql第四版P190~204 学习记录:联接查询:  对于Union查询,mysql先把一系列单个查询放在临时表,然后再重新读出临时表中的数据完成Union查询。在Mysql的概念中,联接......
  • Synchronized,我要一层一层剥开你的心
    三种应用方式修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁。修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。修饰代码块......
  • Synchronized的作用
    官方解释:同步方法支持一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读取或写入都是通过同步方法完成的。一句话总......
  • 决战圣地玛丽乔亚Day19---
    聚簇索引和非聚簇索引:聚簇和非聚簇的含义是:是否索引和数据进行绑定,即是否需要二次查找才能找到对应的数据值。由于聚簇索引的绑定关系,要求聚簇索引是唯一值,否则不能明确通......