基于对象头的MarkWord存储锁状态,实现获取锁,释放锁以及锁升级
所以首先要了解对象头,在未开启指针压缩情况下:
对象头 = 8byte的MarkWord + 8byte的ClassPointer
开启指针压缩后:
对象头 = 8byte的MarkWord + 4byte的ClassPointer + 4byte的对齐数据
对齐是因为64位的JVM寻址空间是8byte,必须为8byte的整数倍
以下程序可以验证:JDK8自动开启指针压缩
关闭指针压缩:-XX:-UseCompressedOops
测试代码
import org.openjdk.jol.info.ClassLayout;
/**
* 测试对象头
*/
public class T14_Object_Header {
public static void main(String[] args){
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
JVM源码中锁在对象头上的标识枚举
enum { locked_value = 0,//00 轻量级锁
unlocked_value = 1,//01 无锁
monitor_value = 2,//10 监视器锁,也叫膨胀锁,也叫重量级锁
marked_value = 3,//11 GC标记
biased_lock_pattern = 5 //101 偏向锁
};
无锁:刚new出来的对象,无任何锁竞争
偏向锁:一段同步代码一直被一个线程所访问,对象会在对象头上标识该线程,那么该线程会自动获取到锁
自旋锁:多个线程竞争同步代码,会以自旋和CAS的方式获取对象的锁
重量级锁:CAS竞争激烈,升级到操作系统的申请锁,由操作系统决定是否获取到锁
测试代码
JDK6后默认开启偏向锁,但是会延时加载,使用JVM参数取消延时加载
-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
import org.openjdk.jol.info.ClassLayout;
/**
* 测试锁升级 -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
*/
public class T14_Object_Header_None_Lock {
public static void main(String[] args) throws InterruptedException {
Object o = new Object();
System.out.println("before lock");
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o) {
System.out.println("locking...........");
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
System.out.println("after lock");
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
操作:CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。如果A=V,那么把B赋值给V,返回V;如果A!=V,直接返回V
实现:JNI调用native方法:unsafe.compareAndSwapInt(this, valueOffset, expect, update);
底层:lock cmpxchg指令,lock用于多CPU情况下保证单CPU执行操作,cmpxchg用于比较替换
原子性和可见性:多个线程是同步的方式访问临界区的,所以具有天然的原子性和可见性
可重入:如果是一个同步方法调用另外一个同步方法,有一个方法加了锁,另外一个方法也需要加锁,加的是同一把锁也是同一个线程,那这个时候申请仍然会得到该对象的锁
不可逆:锁升级的流程是不可逆转的
同步代码块和同步方法
package com.example.code.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class T15_Sync {
private int count1 = 10;
private int count2 = 10;
public void m1() {
synchronized (this) {
count1--;
System.out.print("count = " + count1 + " ");
}
}
public synchronized void m2() {
count2--; // 等价 synchronized (this)
System.out.print("count = " + count2 + " ");
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
T15_Sync t = new T15_Sync();
for (int i = 0; i < 10; i++) {
executorService.submit(new Thread(t::m1, "t" + i + "m1"));
}
executorService.awaitTermination(3, TimeUnit.SECONDS);
System.out.println("m1结束!!!");
for (int i = 0; i < 10; i++) {
executorService.submit(new Thread(t::m2, "t" + i + "m2"));
}
executorService.awaitTermination(3, TimeUnit.SECONDS);
System.out.println("m2结束!!!");
}
}
同步静态方法
package com.example.code.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class T16_Sync {
private static int count3 = 10;
private static int count4 = 10;
public static void m3() {
synchronized (T16_Sync.class) {
count3--;
System.out.print("count = " + count3 + " ");
}
}
public synchronized static void m4() { // 等价 synchronized (T01_Synchronized.class)
count4--;
System.out.print("count = " + count4 + " ");
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(new Thread(() -> {
T16_Sync.m3();
}, "t" + i + "m3"));
}
executorService.awaitTermination(3, TimeUnit.SECONDS);
System.out.println("m3结束!!!");
for (int i = 0; i < 10; i++) {
executorService.submit(new Thread(() -> {
T16_Sync.m4();
}, "t" + i + "m4"));
}
executorService.awaitTermination(3, TimeUnit.SECONDS);
System.out.println("m4结束!!!");
}
}