再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