基础知识补充
java对象的对象头信息分布:(64位机)
|------------------------------------------------------------------------------|--------------------|
| Mark Word (64 bits) | State |
|------------------------------------------------------------------------------|--------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 | Normal | 无锁
|------------------------------------------------------------------------------|--------------------|
| thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2 | Biased | 偏向锁
|------------------------------------------------------------------------------|--------------------|
| ptr_to_lock_record:62 | lock:2 | Lightweight Locked | 轻量级
|------------------------------------------------------------------------------|--------------------|
| ptr_to_heavyweight_monitor:62 | lock:2 | Heavyweight Locked | 重量级
|------------------------------------------------------------------------------|--------------------|
| | lock:2 | Marked for GC | GC标记
|------------------------------------------------------------------------------|--------------------|
总结下即为:
biased_lock lock 状态
0 01 无锁
1 01 偏向锁
0 00 轻量级锁
0 10 重量级锁
0 11 GC标记
小端存储
咱们使用的电脑普遍都是小端存储:高位的字节 存在内存的高地址中
使用JOL打印的对象头信息应该反着看,即:
反读的单位是字节 也就是8位
unused:1 | age:4 | biased_lock:1 | lock:2 | identity_hashcode:31 0 unused:24
相关JVM参数
偏向锁默认延迟启动(延迟4s左右)
通过JVM的参数来禁用延迟-
XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
打印JVM 参数: -XX:+PrintFlagsFinal
-
intx BiasedLockingBulkRebiasThreshold = 20 {product} 偏向阈值
-
intx BiasedLockingBulkRevokeThreshold = 40 {product} 撤销阈值
上代码
依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.8</version>
</dependency>
</dependencies>
代码
使用:-XX:BiasedLockingStartupDelay=0 启动,开启偏向锁
代码中可以证明偏向锁的批量重偏向和批量撤销
import org.openjdk.jol.info.ClassLayout;
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;
public class JOLExample {
static List<A> list = new ArrayList<A>();
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
public void run() {
for (int i=0;i<100;i++){
A a = new A();
synchronized (a){
list.add(a);
}
}
out.println(" add end --------");
if (list.size() == 100){
A a = list.get(60);
synchronized (a){
try {
this.currentThread().sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
t1.start();
//t1.join();
Thread.sleep(5000);
out.println("before t2 1:" + ClassLayout.parseInstance(list.get(1)).toPrintable());
out.println("before t2 60:" + ClassLayout.parseInstance(list.get(60)).toPrintable());
Thread t2 = new Thread() {
int k=0;
public void run() {
for(A a:list){
synchronized (a){
// System.out.println("22222");
if ( k== 18 || k==26 ){
//轻量锁
out.println("t2 ing ------ K=" + k + " |" + ClassLayout.parseInstance(a).toPrintable());
/**
* 当K 为 20 时, 60 的 epoch 会变为 01 原因:
* 当批量偏向到达阈值时,会进行如下操作:
* 1.会修改Class类对象的中 epoch 字段,为: 01 【没有找到是哪一个字段,无法证明】
* 2.会扫描该Class的所有对象:
* A:如果当前Class的对象,在同步块中,则修改 epoch 的值与 Class类对象中的 epoch 字段相等
* B:如果当前Class的对象,不在同步块中则不进行修改
*
*/
out.println("t2 ing ------ K=" + k + " 60:" + ClassLayout.parseInstance(list.get(60)).toPrintable());
}
}
k++;
if (k==50){
out.println(" t2 end -------------------");
A a1 = list.get(80);
synchronized (a1){
try {
this.currentThread().sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
};
t2.start();
//t2.join();
Thread.sleep(5000);
out.println("main ing ---- 80:" + ClassLayout.parseInstance(list.get(80)).toPrintable());
Thread t3 = new Thread() {
int k=0;
public void run() {
for(A a:list){
k++;
if (k > 20){
synchronized (a){
if ( k == 26 || k == 45 ){
//轻量锁
out.println("T3 ing ------ K=" + k + " |" + ClassLayout.parseInstance(a).toPrintable());
/**
* 26 偏向 45 轻量
* 当T3 线程 批量撤销 偏向锁的对象 超过阈值:20 时: (问题: 批量撤销总次数阈值为 40 ,这里为什么是 20 ? 因为 T2 线程 在进行重偏向时, 已撤销了20次【前20个对象】,这里只剩下 20 次)
* 会扫描对正在同步块中的对象 。对所有对象进行撤销 偏向锁 ,全部置为 轻量级锁 ,因此 当K 为 45时,已发生批量 撤销, 80 已置为 轻量级锁
*/
out.println("T3 ing ------ K=" + k + " 80:" + ClassLayout.parseInstance(list.get(80)).toPrintable());
}
}
if (k==45){
return;
}
}
}
}
};
t3.start();
t3.join();
// 轻量级锁
out.println("main ing ---- 80:" + ClassLayout.parseInstance(list.get(80)).toPrintable());
}
class A {
int i=0;
}