我们都知道synchroized可以让线程同步,所谓同步,就是同一时刻,只能有一个线程执行这段代码。
synchronized:
1.锁对象
public class Main {
private Main main;
public Main(Main main) {
this.main = main;
}
public void method(){
synchronized(main){
System.out.println("这是同步代码块---锁当前对象");
}
}
}
2.锁方法
public synchronized void method(){
System.out.println("同步方法--锁this对象");
}
3.锁class对象
public synchronized static void method(){
System.out.println("同步静态方法--锁当前类的class对象");
}
那么synchronized到底是锁什么呢,我们都知道synchronized是锁对象头,那么到底是锁什么呢。
我们先来看下java中对象的格式布局,java中都有固定格式的对象头,对象头中有个Mark Word ,64位虚拟中,Mark Word有64个bit。
25bit | 31bit | 1bit | 4bit | 1bit (偏向锁标识) | 2bit(锁标志位) |
---|---|---|---|---|---|
unused | hashCode | unused | 分带年龄 | 偏向锁标致 | 锁标识位 |
我们无需关注太多,只需要只知道在对象头中 有2个bit用来标志锁,有1个bit标志是否偏向锁
1bit (偏向锁标识 | 2bit(锁标志位 |
---|---|
1:偏向锁 | 01:无锁 |
0:非偏向锁 | 00:轻量级锁 |
10:重量级锁 | |
11:GC标记 |
所以synchronized给对象加锁,就是修改对象锁标志位数值,所有的线程都是根据这个锁标志位的数值进行判断,这个对象是否上锁
那么synchronized锁是如何升级的
在jdk1.6之之前,synchronized只有无锁和重量级锁两个级别,在jdk1.6之后,优化了性能,synchronized锁状态分为无锁、偏向锁、轻量级锁、重量级锁几个状态
- 无锁: 指没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。
- 偏向锁: 指当一段同步代码一直被同一个线程所访问时,即不存在多个线程的竞争时,那么该线程在后续访问时便会自动获得锁,从而降低获取锁带来的消耗,即提高性能。
- 轻量级锁: 指当锁是偏向锁的时候,却被另外的线程所访问,此时偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,线程不会阻塞,从而提高性能
- 重量级锁: 指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。
用程序测试锁的升级
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
默认情况下新建对象是无锁状态
![public class Main {
//根据对象输出对象头的64个bit
public static void main(String\[\] args) {
Object o=new Object();
//输出对象头
String str= ClassLayout.parseInstance(o).toPrintable();
System.out.println(str);
}
}](https://img-blog.csdnimg.cn/20201019001615801.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzgxNTg4Mg==,size_16,color_FFFFFF,t_70#pic_center)
输出:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 09 00 00 00 (00001001 00000000 00000000 00000000) (9)
4 4 (object header) 70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
偏向锁
默认开启,但是要延迟4秒,可以在创建对象前等待5秒
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
Object obj = new Object();
//开启一个线程,在线程中枷锁
Thread t1 = new Thread(() -> {
//使用synchronized 锁obj
synchronized (obj) { //锁obj对象 偏向锁
System.out.println("偏向锁状态");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
});
启动i线程
t1.start();
}
结果:
偏向锁状态
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0d 48 ad 15 (00001101 01001000 10101101 00010101) (363677709)
4 4 (object header) 70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
轻量级锁
接下来在t1 结束后,使用synchronized锁obj对象,由于是t1线程和主线程交替执行,所以进入轻量级锁
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
Object obj=new Object();
//开启一个线程,在线程中枷锁
Thread t1=new Thread(()->{
//使用synchronized 锁obj
synchronized (obj){//锁obj对象 偏向锁
System.out.println("偏向锁状态");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
});
//启动线程
t1.start();
t1.join();
synchronized (obj){
System.out.println("轻量级锁状态");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
输出:
偏向锁状态
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0d 10 ed 16 (00001101 00010000 11101101 00010110) (384634893)
4 4 (object header) 70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
轻量级锁状态
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 20 f5 27 01 (00100000 11110101 00100111 00000001) (19395872)
4 4 (object header) 70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
重量级锁
接下来在主线程锁住obj对象之后,等待两秒 模拟重操作,开启线程t2,让t2线程尝试获取obj锁,就进入重量级锁状态
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
Object obj = new Object();
//开启一个线程,在线程中枷锁
Thread t1 = new Thread(() -> {
//使用synchronized 锁obj
synchronized (obj) {//锁obj对象 偏向锁
System.out.println("偏向锁状态");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
});
//启动线程
t1.start();
t1.join();
Thread t2 = new Thread(() -> {
try {
//等主线程拿到锁
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
System.out.println("重量级锁状态");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
});
t2.start();//启动线程t2 尝试获取obj的锁
synchronized (obj) {
System.out.println("轻量级锁状态");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
//主线程不要释放锁
Thread.sleep(2000);
}
}
输出:
偏向锁状态
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0d 20 c8 15 (00001101 00100000 11001000 00010101) (365436941)
4 4 (object header) 70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
轻量级锁状态
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 1c fb b4 00 (00011100 11111011 10110100 00000000) (11860764)
4 4 (object header) 70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
重量级锁状态
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0e e1 98 02 (00001110 11100001 10011000 00000010) (43573518)
4 4 (object header) 70 0d 06 16 (01110000 00001101 00000110 00010110) (369495408)
Instance size: 8 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
无锁状态 | 偏向锁状态 | 轻量级锁状态 | 重量级锁状态 |
---|---|---|---|
0(偏向锁标志位)01(锁标志位) | 101 | 000 | 010 |
以上就是synchronized锁升级测试。