synchronized锁的状态总共有四种,无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争( 无锁 —> 偏向锁 —> 轻量级 —> 重量级锁)
锁可以从偏向锁升级到轻量级锁,再升级的重量级锁,但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。
乐观锁:
乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。
悲观锁:
悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。
自旋锁(CAS):
自旋锁就是让不满足条件的线程等待一段时间,而不是立即挂起。看持有锁的线程是否能够很快释放锁。怎么自旋呢?其实就是一段没有任何意义的循环。虽然它通过占用处理器的时间来避免线程切换带来的开销,但是如果持有锁的线程不能在很快释放锁,那么自旋的线程就会浪费处理器的资源,因为它不会做任何有意义的工作。所以,自旋等待的时间或者次数是有一个限度的,如果自旋超过了定义的时间仍然没有获取到锁,则该线程应该被挂起。JDK1.6中-XX:+UseSpinning开启; -XX:PreBlockSpin=10 为自旋次数; JDK1.7后,去掉此参数,由jvm控制;
轻量级锁
轻量级锁的使用场景:如果一个对象虽然有多线程要加锁,但加锁的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化。轻量级锁对使用者是透明的,即语法仍然是 synchronized
。
轻量级锁考虑的是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。因为阻塞线程需要CPU从用户态转到内核态,代价较大,如果刚刚阻塞不久这个锁就被释放了,那这个代价就有点得不偿失了,因此这个时候就干脆不阻塞这个线程,让它自旋这等待锁释放
轻量锁的升级时机 : 当关闭偏向锁功能或多线程竞争偏向锁会导致偏向锁升级为轻量级锁
线程1获取轻量级锁时会先把锁对象的对象头MarkWord复制一份到线程1的栈帧中创建的用于存储锁记录的空间(Lock Record),然后使用CAS把对象头中的内容替换为线程1存储的锁记录的地址;
如果在线程1复制对象头的同时(在线程1CAS之前),线程2也准备获取锁,复制了对象头到线程2的锁记录空间(Lock Record)中,但是在线程2CAS的时候,发现线程1已经把对象头换了,线程2的CAS失败,那么线程2就尝试使用自旋锁来等待线程1释放锁。但是如果自旋的时间太长也不行,因为自旋是要消耗CPU的,因此自旋的次数是有限制的,如果自旋次数到了线程1还没有释放锁,或者线程1还在执行,线程2还在自旋等待,这时又有一个线程3过来竞争这个锁对象,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。
public class LightweightLock {
static final Object obj = new Object();
public static void method1() {
synchronized (obj) {
// 同步块 A
method2();
}
}
public static void method2() {
synchronized (obj) {
// 同步块 B
}
}
}
- 创建锁记录(
Lock Record
)对象,每个线程都的栈帧都会包含一个锁记录的结构,内部可以存储锁定对象的Mark Word
- 让锁记录中
Object reference
指向锁对象,并尝试用 cas 替换 Object 的Mark Word
,将Mark Word
的值存入锁记录
- 如果 cas 替换成功,对象头中存储了锁记录地址和状态 00 (将recoder地址和markd word互换),表示由该线程给对象加锁,这时图示如下
- 如果 cas 失败,有两种情况
- 如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程(详见锁膨胀)
- 如果是自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数
- 当退出 synchronized 代码块(解锁时)如果有取值为 null 的锁记录,表示有重入,这时重置锁记录,表示重入计数减一
- 当退出
synchronized
代码块(解锁时)锁记录的值不为 null,这时使用 cas 将Mark Word
的值恢复给对象头,
- 成功,则解锁成功
失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程
锁膨胀
如果在尝试加轻量级锁的过程中,CAS 操作无法成功,这时一种情况就是有其它线程(两个及以上)为此对象加上了轻量级锁(有竞争)且线程经过自旋后仍然没有获取到锁,这时需要进行锁膨胀,将轻量级锁变为重量级锁。 ```java public class LockCoarsening { public static void main(String[] args) {
Coarsening c = new Coarsening();
new Thread(() -> {
c.thread1();
}, "t1").start();
new Thread(() -> {
c.thread2();
}, "t2").start();
}
}
class Coarsening { public void thread1() { synchronized (this) { log.info(“{}获取到锁”, Thread.currentThread().getName()); sleep(1); log.info(“{}释放锁”, Thread.currentThread().getName()); } }
public void thread2() {
synchronized (this) {
log.info("{}获取到锁", Thread.currentThread().getName());
log.info("{}释放锁", Thread.currentThread().getName());
}
}
}
2021-09-30 09:02:19.191 [t1] INFO com.song.synchronize.Coarsening - t1获取到锁 2021-09-30 09:02:20.204 [t1] INFO com.song.synchronize.Coarsening - t1释放锁 //经过1s后t2才获取到锁 2021-09-30 09:02:20.204 [t2] INFO com.song.synchronize.Coarsening - t2获取到锁 2021-09-30 09:02:20.205 [t2] INFO com.song.synchronize.Coarsening - t2释放锁
1. 当`t2`进行轻量级加锁时,`t1`已经对该对象加了轻量级锁
![image.png](https://cdn.nlark.com/yuque/0/2021/png/22353188/1632964815185-77b60652-8529-4c40-8002-580696aa67b6.png#height=317&id=u9d6d35bd&margin=%5Bobject%20Object%5D&name=image.png&originHeight=633&originWidth=1627&originalType=binary&ratio=1&size=93188&status=done&style=none&width=813.5)
2. 这时`t2`加轻量级锁失败,进入锁膨胀流程,`t2`为 Object 对象申请 Monitor 锁,让 Object 指向重量级锁地址,然后自己进入 Monitor 的 EntryList BLOCKED
![image.png](https://cdn.nlark.com/yuque/0/2021/png/22353188/1632965103749-1e49478e-e121-4055-bd78-415147ba9106.png#height=338&id=u9995f620&margin=%5Bobject%20Object%5D&name=image.png&originHeight=676&originWidth=1788&originalType=binary&ratio=1&size=83468&status=done&style=none&width=894)
3. 当`t1`退出同步块解锁时,使用 cas 将 Mark Word 的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照 Monitor 地址找到 Monitor 对象,设置 Owner 为 null,唤醒 EntryList 中 BLOCKED 线程
<a name="pvnAB"></a>
# 偏向锁
偏向锁是一种针对加锁操作的优化手段,它的意思是这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。因为在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,因此为了减少同一线程获取锁(会涉及到一些CAS操作,耗时)的代价而引入偏向锁。<br />偏向锁的核心思想是,如果一个线程获得了锁,那么锁就进入偏向模式,此时Mark Word 的结构也变为偏向锁结构,当这个线程再次请求锁时,无需再做任何同步操作,即获取锁的过程,对于没有锁竞争的场合,偏向锁有很好的优化效果,但是对于锁竞争比较激烈的场合,偏向锁就失效了,偏向锁失败后,并不会立即膨胀为重量级锁,而是先升级为轻量级锁。简而言之,轻量级锁在没有竞争时只有一个线程使用,每次重入仍然需要执行 CAS 操作。Java 6 中引入了偏向锁来做进一步优化:只有第一次使用 CAS 将线程 ID 设置到对象的 `Mark Word` 头,之后发现这个线程 ID 是自己的就表示没有竞争,不用重新 CAS。以后只要不发生竞争,这个对象就归该线程所有。<br />**偏向锁的目的是消除数据在无竞争情况下的CAS操作,进一步提高程序的运行性能。偏向锁可以通过参数**`-XX:+UseBiasedLocking`**控制偏向锁是否启用。**
```java
public class BiasedLock {
static final Object obj = new Object();
/**
* 需要使用-XX:BiasedLockingStartupDelay=0参数关闭偏向锁延时
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
BiasedLock ll = new BiasedLock();
Thread t1 = new Thread(() -> {
ll.method1();
}, "t1");
t1.start();
t1.join();
}
public void method1() {
synchronized (obj) {
log.info("进入method1,obj {}", ClassLayout.parseInstance(obj).toPrintableSimple());
method2();
}
}
public void method2() {
synchronized (obj) {
log.info("进入method2,obj {}", ClassLayout.parseInstance(obj).toPrintableSimple());
method3();
}
}
public void method3() {
synchronized (obj) {
log.info("进入method3,obj {}", ClassLayout.parseInstance(obj).toPrintableSimple());
}
}
一个对象创建时如果开启了偏向锁(默认开启),那么对象创建后,markword
值为 0x05 即最后 3 位为 101,这时它的thread
、epoch
、age
都为0偏向锁是默认是延迟的(参考markd work头),不会在程序启动时立即生效,如果想避免延迟,可以加 VM 参数-XX:BiasedLockingStartupDelay=0
来禁用延迟,如果没有开启偏向锁,那么对象创建后,markword
值为 0x01
即最后 3 位为 001,这时它的 hashcode
、age
都为 0,第一次用到 hashcode
时才会赋值 。
测试偏向锁
利用 jol 第三方工具来查看对象头信息 ,为使输出信息更简洁,重写了其中的 ClassLayout._parseInstance_(obj).toPrintableSimple()
方法
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
/**
* 处于偏向锁的对象解锁后,线程 id 仍存储于对象头中
**/
public static void test() throws InterruptedException {
Object obj = new Object();
log.info("进入synchronized前 {}", ClassLayout.parseInstance(obj).toPrintableSimple());
Thread t1 = new Thread(() -> {
synchronized (obj) {
log.info("进入synchronized {}", ClassLayout.parseInstance(obj).toPrintableSimple());
}
}, "t1");
t1.start();
t1.join();
log.info("进入synchronized后 {}", ClassLayout.parseInstance(obj).toPrintableSimple());
}
2021-09-30 14:40:37.127 [main] INFO - 进入synchronized前
(object header: mark) 00000000 00000000 00000000 00000101 (biasable; age: 0)
2021-09-30 14:40:37.131 [t1] INFO - 进入synchronized
(object header: mark) 00100110 00011011 11100000 00000101 (biased: 0x000000008e4986f8; epoch: 0; age: 0)
2021-09-30 14:40:37.131 [main] INFO - 进入synchronized后
(object header: mark) 00100110 00011011 11100000 00000101 (biased: 0x000000008e4986f8; epoch: 0; age: 0)
禁用偏向锁
在上面测试代码运行时在添加 VM 参数-XX:-UseBiasedLocking
禁用偏向锁
输出
2021-09-30 14:43:17.588 [main] INFO - 进入synchronized未加锁状态
(object header: mark) 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 14:43:17.591 [t1] INFO - 进入synchronized轻量级锁状态
(object header: mark) 11101100 10101111 11110100 01110000 (thin lock: 0x00000016ecaff470)
2021-09-30 14:43:17.591 [main] INFO - 进入synchronized后解除加锁状态
(object header: mark) 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
撤销偏向锁
调用HashCode方法后偏向锁被撤销
调用了对象的 hashCode,偏向锁的对象 MarkWord 中存储的是线程 id,如果调用 hashCode 会导致偏向锁被撤销,轻量级锁会在锁记录中记录 hashCode,重量级锁会在 Monitor 中记录 hashCode。
public static void test() throws InterruptedException {
Object obj = new Object();
log.info("进入synchronized\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
Thread t1 = new Thread(() -> {
obj.hashCode();
log.info("hascode之后\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
synchronized (obj) {
log.info("进入synchronized\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
}
}, "t1");
t1.start();
t1.join();
log.info("进入synchronized后\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
}
2021-09-30 14:47:58.067 [main] INFO - 进入synchronized 无锁状态
(object header: mark) 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 14:47:58.070 [t1] INFO - hascode之后 无锁状态但是markword存储了hashcode信息
(object header: mark) 00111010 11101000 11011001 00000001 (hash: 0x683ae8d9; age: 0)
2021-09-30 14:47:58.071 [t1] INFO - 进入synchronized 轻量级锁,hashcode被替换为线程id
(object header: mark) 11100101 10111111 11110000 01110000 (thin lock: 0x00000035e5bff070)
2021-09-30 14:47:58.071 [main] INFO - 进入synchronized后 无锁状态,markword存储了hashcode
(object header: mark) 00111010 11101000 11011001 00000001 (hash: 0x683ae8d9; age: 0)
有其他线程竞争同一把锁(错开竞争)
public static void main(String[] args) throws InterruptedException {
BiasedLock ll = new BiasedLock();
Thread t1 = new Thread(() -> {
ll.method1();
}, "t1");
Thread t2 = new Thread(() -> {
ll.method1();
}, "t2");
t1.start();
t1.join();
t2.start();
t2.join();
log.info("进入main,obj {}", ClassLayout.parseInstance(obj).toPrintableSimple());
}
//起出只有线程1使用锁,所以是偏向锁
2021-09-30 14:53:39.916 [t1] INFO - 进入method1,obj (object header: mark)
00010111 00100001 00111000 00000101 (biased: 0x000000008105c84e; epoch: 0; age: 0)
2021-09-30 14:53:39.919 [t1] INFO - 进入method2,obj (object header: mark)
00010111 00100001 00111000 00000101 (biased: 0x000000008105c84e; epoch: 0; age: 0)
2021-09-30 14:53:39.919 [t1] INFO - 进入method3,obj (object header: mark)
00010111 00100001 00111000 00000101 (biased: 0x000000008105c84e; epoch: 0; age: 0)
//线程2 将线程1的偏向锁升级为轻量级锁
2021-09-30 14:53:39.920 [t2] INFO - 进入method1,obj (object header: mark)
11000101 00011111 11101101 10111000 (thin lock: 0x000000bdc51fedb8)
2021-09-30 14:53:39.920 [t2] INFO - 进入method2,obj (object header: mark)
11000101 00011111 11101101 10111000 (thin lock: 0x000000bdc51fedb8)
2021-09-30 14:53:39.921 [t2] INFO - 进入method3,obj (object header: mark)
11000101 00011111 11101101 10111000 (thin lock: 0x000000bdc51fedb8)
//释放后变为无锁
2021-09-30 14:53:39.921 [main] INFO - 进入main,obj (object header: mark)
00000000 00000000 00000000 00000001 (non-biasable; age: 0)
使用wait/notify
/**
* 测试wait / notify对偏向锁的影响
*
* @throws InterruptedException
*/
public static void testWait() {
Object obj = new Object();
log.info("进入synchronized\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
new Thread(() -> {
synchronized (obj) {
try {
log.info("wait前\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
obj.wait();
log.info("notify后\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (BiasedLock.class) {
BiasedLock.class.notify();
}
}, "t1").start();
new Thread(() -> {
Sleeper.sleep(2);
synchronized (obj) {
log.info("notify前\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
obj.notify();
}
}, "t2").start();
Sleeper.sleep(3);
log.info("主线程\n {}", ClassLayout.parseInstance(obj).toPrintableSimple());
}
2021-09-30 15:13:48.691 [main] INFO - 进入synchronized 偏向锁可用
(object header: mark) 00000000 00000000 00000000 00000101 (biasable; age: 0)
2021-09-30 15:13:48.695 [t1] INFO - wait前 t1的偏向锁
(object header: mark) 00100101 01110101 00101000 00000101 (biased: 0x000000006cc95d4a; epoch: 0; age: 0)
2021-09-30 15:13:50.701 [t2] INFO - notify前 升级为重量级锁
(object header: mark) 00100010 11101100 01001110 11101010 (fat lock: 0x000001b322ec4eea)
2021-09-30 15:13:50.702 [t1] INFO - notify后 撤销偏向锁改为重量级锁
(object header: mark) 01111111 00100010 01001111 01001010 (fat lock: 0x0000010c7f224f4a)
2021-09-30 15:13:51.710 [main] INFO - 主线程 释放锁撤销偏向锁
(object header: mark) 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
批量重偏向
如果对象虽然被多个线程访问,但没有竞争,这时偏向了线程 T1 的对象仍有机会重新偏向 T2,重偏向会重置对象的 Thread ID当撤销偏向锁阈值超过 20 次后,jvm 会这样觉得,我是不是偏向错了呢,于是会在给这些对象加锁时重新偏向至加锁线程 **-XX:BiasedLockingBulkRebiasThreshold=20 **
默认偏向锁批量重偏向阈值
/**
* 测试批量重偏向
*/
public static void testBatchBiased() {
List<Object> list = new Vector<>();
new Thread(() -> {
for (int i = 0; i < 30; i++) {
Object obj = new Object();
synchronized (obj) {
list.add(obj);
log.info("{} {}", i + 1, ClassLayout.parseInstance(obj).toPrintableSimple());
}
}
synchronized (list) {
list.notify();
}
}, "t1").start();
new Thread(() -> {
synchronized (list) {
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
log.info("{}加锁前{}", i + 1, ClassLayout.parseInstance(obj).toPrintableSimple());
synchronized (obj) {
log.info("{} {}", i + 1, ClassLayout.parseInstance(obj).toPrintableSimple());
}
log.info("{}加锁后{}", i + 1, ClassLayout.parseInstance(obj).toPrintableSimple());
}
}, "t2").start();
}
输出结果
2021-09-30 16:09:59.370 [t1] INFO - 1 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 2 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 3 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 4 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 5 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 6 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 7 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 8 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.374 [t1] INFO - 9 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 10 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 11 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 12 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 13 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 14 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 15 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 16 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.375 [t1] INFO - 17 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 18 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 19 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 20 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 21 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 22 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 23 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 24 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.376 [t1] INFO - 25 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 26 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 27 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 28 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 29 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t1] INFO - 30 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t2] INFO - 1加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.377 [t2] INFO - 1 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.378 [t2] INFO - 1加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.378 [t2] INFO - 2加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.378 [t2] INFO - 2 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.378 [t2] INFO - 2加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.378 [t2] INFO - 3加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.378 [t2] INFO - 3 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.378 [t2] INFO - 3加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 4加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 4 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.379 [t2] INFO - 4加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 5加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 5 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.379 [t2] INFO - 5加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 6加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.379 [t2] INFO - 6 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.379 [t2] INFO - 6加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 7加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 7 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.380 [t2] INFO - 7加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 8加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 8 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.380 [t2] INFO - 8加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 9加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.380 [t2] INFO - 9 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.381 [t2] INFO - 9加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 10加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 10 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.381 [t2] INFO - 10加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 11加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 11 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.381 [t2] INFO - 11加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.381 [t2] INFO - 12加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 12 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.382 [t2] INFO - 12加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 13加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 13 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.382 [t2] INFO - 13加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 14加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.382 [t2] INFO - 14 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.382 [t2] INFO - 14加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 15加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 15 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.383 [t2] INFO - 15加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 16加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 16 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.383 [t2] INFO - 16加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 17加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.383 [t2] INFO - 17 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.384 [t2] INFO - 17加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 18加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 18 00000000 00000000 00000000 10111101 10101010 11101111 11110100 00000000 (thin lock: 0x000000bdaaeff400)
2021-09-30 16:09:59.384 [t2] INFO - 18加锁后 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 (non-biasable; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 19加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 19 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.384 [t2] INFO - 19加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 20加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 20 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 20加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 21加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 21 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 21加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.385 [t2] INFO - 22加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 22 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 22加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 23加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 23 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 23加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 24加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.386 [t2] INFO - 24 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 24加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 25加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 25 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 25加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 26加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 26 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.387 [t2] INFO - 26加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 27加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 27 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 27加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 28加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 28 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 28加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 29加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.388 [t2] INFO - 29 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.389 [t2] INFO - 29加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.389 [t2] INFO - 30加锁前 00000000 00000000 00000010 00100111 00101000 00110000 00000000 00000101 (biased: 0x0000000089ca0c00; epoch: 0; age: 0)
2021-09-30 16:09:59.389 [t2] INFO - 30 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
2021-09-30 16:09:59.389 [t2] INFO - 30加锁后 00000000 00000000 00000010 00100111 00101000 00110000 00100001 00000101 (biased: 0x0000000089ca0c08; epoch: 0; age: 0)
分析结果:t1
线程经过30次的迭代后将30个obj对象变成了偏向t1
线程的锁,t1
结束运行,t2
开始执行,在前18次加锁的时候都是将偏向锁重置为无锁,第19次开始,开始将锁重置为t2
线程的偏向锁(线程id改变了)
批量撤销
当撤销偏向锁阈值超过 40 次后,jvm 会这样觉得,自己确实偏向错了,根本就不该偏向。于是整个类的所有对象都会变为不可偏向的,新建的对象也是不可偏向的 ,偏向锁的撤销实际上指的是将偏向锁变成轻量级锁的过程,.
-XX:BiasedLockingBulkRevokeThreshold=40
默认偏向锁批量撤销阈值
- 批量重偏向和批量撤销是针对类的优化,和对象无关。
- 偏向锁重偏向一次之后不可再次重偏向。
当某个类已经触发批量撤销机制后,JVM会默认当前类产生了严重的问题,剥夺了该类的新实例对象使用偏向锁的权利
/** * 测试批量撤销偏向锁 */ public static void testBatchCancle() throws InterruptedException { List<Dog> list = new Vector<>(); //线程1添加偏向锁 int loopNumber = 39; t1 = new Thread(() -> { for (int i = 0; i < loopNumber; i++) { Dog o = new Dog(); list.add(o); synchronized (o) { log.info("{} {}", i + 1, ClassLayout.parseInstance(o).toPrintableSimple()); } } //唤醒t2线程 LockSupport.unpark(t2); }, "t1"); t2 = new Thread(() -> { //t2阻塞,等待t1执行完 LockSupport.park(); for (int i = 0; i < loopNumber; i++) { Dog o = list.get(i); synchronized (o) { log.info("{} {}", i + 1, ClassLayout.parseInstance(o).toPrintableSimple()); } } LockSupport.unpark(t3); }, "t2"); t3 = new Thread(() -> { //t3阻塞,等待t2执行完 LockSupport.park(); for (int i = 0; i < loopNumber; i++) { Dog o = list.get(i); synchronized (o) { log.info("{} {}", i + 1, ClassLayout.parseInstance(o).toPrintableSimple()); } } }, "t3"); t1.start(); t2.start(); t3.start(); t3.join(); Dog o = new Dog(); log.info(" {}", ClassLayout.parseInstance(o).toPrintableSimple()); }
锁消除
锁消除即删除不必要的加锁操作。JVM在运行时,对一些在代码上要求同步,但是被检测到不可能存在共享数据竞争情况的锁进行消除。根据代码逃逸技术,如果判断到一段代码中,堆上的数据不会逃逸出当前线程,那么就可以认为这段代码是线程安全的,无需加锁。
static int x = 0; public void a() throws Exception { x++; } public void b() throws Exception { //对象o没有发生逃逸 Object o = new Object(); synchronized (o) { x++; } }
逃逸分析
在编程语言的编译优化原理中,分析指针动态范围的方法称之为逃逸分析。通俗一点讲,当一个对象的指针被多个方法或线程引用时,我们称这个指针发生了逃逸。JVM判断新创建的对象是否逃逸的依据有两个:
对象被赋值给堆中对象的字段或者类的静态变量
- 对象被传进了不确定的代码中去运行
- 方法逃逸
一个对象在方法中被定义,但却被方法以外的其他代码使用。如传参到其他方法中等可能导致此情况发生。
- 线程逃逸
一个对象由某个线程在方法中被定义,但却被其他线程访问。如类变量、公用的或有get、set方法的实例变量等 - 逃逸分析具体配置
- 开启逃逸分析(JDK8中,逃逸分析默认开启。)
-XX:+DoEscapeAnalysis - 关闭逃逸分析
-XX:-DoEscapeAnalysis - 逃逸分析结果展示
-XX:+PrintEscapeAnalysis
- 开启逃逸分析(JDK8中,逃逸分析默认开启。)
案例 ```java public class EscapeTest {
public static Object globalVariableObject;
public Object instanceObject;
public void globalVariableEscape(){
globalVariableObject = new Object(); // 静态变量,外部线程可见,发生逃逸
}
public void instanceObjectEscape(){
instanceObject = new Object(); // 赋值给堆中实例字段,外部线程可见,发生逃逸
}
public Object returnObjectEscape(){
return new Object(); // 返回实例,外部线程可见,发生逃逸
}
public void noEscape(){
Object noEscape = new Object(); // 仅创建线程可见,对象无逃逸
}
}
<a name="SZVuE"></a>
# 锁粗化
一个程序对同一个锁不间断、高频地请求、同步与释放,会消耗掉一定的系统资源,这样高频的锁请求就不利于系统性能的优化了。**锁粗化就是把很多次锁的请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗。**<br />一种极端的情况如下:
```java
public void doSomethingMethod(){
synchronized(lock){
//do some thing
}
//这是还有一些代码,做其它不需要同步的工作,但能很快执行完毕
synchronized(lock){
//do other thing
}
}
上面的代码是有两块需要同步操作的,但在这两块需要同步操作的代码之间,需要做一些其它的工作,而这些工作只会花费很少的时间,那么我们就可以把这些工作代码放入锁内,将两个同步代码块合并成一个,以降低多次锁请求、同步、释放带来的系统性能消耗,合并后的代码如下:
public void doSomethingMethod(){
//进行锁粗化:整合成一次锁请求、同步、释放
synchronized(lock){
//do some thing
//做其它不需要同步但能很快执行完的工作
//do other thing
}
}
注意:这样做是有前提的,就是中间不需要同步的代码能够很快速地完成,如果不需要同步的代码需要花很长时间,就会导致同步块的执行需要花费很长的时间,这样做也就不合理了。
另一种需要锁粗化的极端的情况是:
for(int i=0;i<size;i++){
synchronized(lock){
}
}
上面代码每次循环都会进行锁的请求、同步与释放,看起来貌似没什么问题,且在jdk内部会对这类代码锁的请求做一些优化,但是还不如把加锁代码写在循环体的外面,这样一次锁的请求就可以达到我们的要求,除非有特殊的需要:循环需要花很长时间,但其它线程等不起,要给它们执行的机会。
synchronized(lock){
for(int i=0;i<size;i++){
}
}
重量级锁
重量级锁通过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。主要是,当系统检查到锁是重量级锁之后,会把等待想要获得锁的线程进行阻塞,被阻塞的线程不会消耗cup。但是阻塞或者唤醒一个线程时,都需要操作系统来帮忙,这就需要从用户态转换到内核态,而转换状态是需要消耗很多时间的,有可能比用户执行代码的时间还要长。这就是说为什么重量级线程开销很大的。