升级过程
synchronized锁升级分为三个过程:偏向锁->轻量级锁->重量级锁
偏向锁和轻量级锁都可以理解为自旋,也就是**while(true){}**实现的
而重量级锁是java虚拟机交给操作系统去实现的,所以非常损耗性能
验证
通过写一些代码,让锁的状态具现在视野中
synchronized的锁是存在于对象头中的,最后两位是锁种类,倒数第一位是偏向锁位
安装工具
<!--查看对象头工具-->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
偏向锁
import java.util.concurrent.TimeUnit;
import org.openjdk.jol.info.ClassLayout;
public class Testsynchronized {
public static void main(String[] args) throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o) {
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
}
因为jvm在启动的时候,自身有一些jar包中的类,也会使用synchronized修饰,所以会暂停偏向锁使用5秒
可以看到,最后三位为
轻量级锁
import org.openjdk.jol.info.ClassLayout;
public class Testsynchronized {
public static void main(String[] args) throws InterruptedException {
// TimeUnit.SECONDS.sleep(5);
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o) {
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
}
因为jvm把偏向锁禁了,所以显示轻量级锁
重量级锁
import java.util.concurrent.TimeUnit;
import org.openjdk.jol.info.ClassLayout;
public class Testsynchronized2 {
public static void main(String[] args) throws InterruptedException {
// TimeUnit.SECONDS.sleep(5);
Object o = new Object();
Thread t1 = new Thread(() -> {
synchronized (o) {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println(ClassLayout.parseInstance(o).toPrintable());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(() -> {
synchronized (o) {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println(ClassLayout.parseInstance(o).toPrintable());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
可看到,在程序长时间占用代码块时,锁会升级为重量级锁;但是在线程争抢特别激烈的地方也会升级为重量级锁
总结
因为synchronized是不公平锁,而且会有锁升级过程,升级为重量级锁时由于操作系统介入导致性能下降,所以synchronized一般会应用在线程争抢不激烈、程序执行时间较快的地方