先说答案, 锁的批量重偏向是针对类的,且只能触发一次,撤销阈值20次是指撤销19个对象偏向锁后再来一个对象需要撤销才会触发锁的批量重偏向,实际会撤销19个。
测试过程如下:
建立spring项目,要有依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
测试一
package com.itheima.mybatis;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;
import java.util.Vector;
import java.util.concurrent.locks.LockSupport;
/**
* @author 名
* @date 2024/8/2-18:44
*/
@Slf4j
public class Test4 {
public static void main(String[] args) throws InterruptedException {
Test4.test4();
}
static Thread t1, t2, t3;
private static void test4() throws InterruptedException {
Vector<Dog> list = new Vector<>();
int loopNumber = 60 ;
t1 = new Thread(() -> {
for (int i = 0; i < loopNumber; i++) {
Dog d = new Dog();
list.add(d);
synchronized (d) {
log.debug(i+1 + "号" + ClassLayout.parseInstance(d).toPrintable());
}
}
LockSupport.unpark(t2);
}, "t1");
t1.start();
t2 = new Thread(() -> {
LockSupport.park();
log.debug("===============> ");
for (int i = 0; i < loopNumber; i++) {
Dog d = list.get(i);
synchronized (d) {
log.debug(i+1 + "号" + ClassLayout.parseInstance(d).toPrintable());
}
}
LockSupport.unpark(t3);
}, "t2");
t2.start();
t3 = new Thread(() -> {
LockSupport.park();
log.debug("===============> ");
for (int i = 0; i < loopNumber; i++) {
Dog d = list.get(i);
synchronized (d) {
log.debug(i+1 + "号" + ClassLayout.parseInstance(d).toPrintable());
}
}
}, "t3");
t3.start();
}
}
class Dog{}
线程t1建立60个对象,并让60个对象加锁(偏向锁偏向t1),线程t2,t3分别对60个对象加锁,多线程执行顺序为t1->t2->t3。
测式结果:
可以看到结果,t2撤销19个偏向锁后(1号至19号),第20次触发批量重偏向,而t3在第20次没有触发批量重偏向,说明撤销阈值20是针对类的不是针对线程的,且只能触发一次。
测是二:
package com.itheima.mybatis;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;
import java.util.Vector;
import java.util.concurrent.locks.LockSupport;
/**
* @author 名
* @date 2024/8/2-18:44
*/
@Slf4j
public class Test4 {
public static void main(String[] args) throws InterruptedException {
Test4.test4();
}
static Thread t1, t2, t3;
private static void test4() throws InterruptedException {
Vector<Dog> list = new Vector<>();
int loopNumber = 29 ;
t1 = new Thread(() -> {
for (int i = 0; i < loopNumber; i++) {
Dog d = new Dog();
list.add(d);
synchronized (d) {
log.debug(i+1 + "号" + ClassLayout.parseInstance(d).toPrintable());
}
}
LockSupport.unpark(t2);
}, "t1");
t1.start();
t2 = new Thread(() -> {
LockSupport.park();
log.debug("===============> ");
for (int i = 0; i < loopNumber-10; i++) {
Dog d = list.get(i);
synchronized (d) {
log.debug(i+1 + "号" + ClassLayout.parseInstance(d).toPrintable());
}
}
LockSupport.unpark(t3);
}, "t2");
t2.start();
t3 = new Thread(() -> {
LockSupport.park();
log.debug("===============> ");
for (int i = 0; i < loopNumber; i++) {
Dog d = list.get(i);
synchronized (d) {
log.debug(i+1 + "号" + ClassLayout.parseInstance(d).toPrintable());
}
}
}, "t3");
t3.start();
}
}
class Dog{}
修改数值,线程t1建立29个对象,并让29个对象加锁(偏向锁偏向t1),线程t2对前19个对象加锁,t3对29个对象加锁,多线程执行顺序为t1->t2->t3。
可以看到线程t2撤销前19个,但因为没有第20个对象,所以没有触发批量重偏向,二线程t3因为有第20个对象加锁所以触发批量重偏向,说明撤销偏向锁19次后,不会触发批量重偏向,只有第20个对象需要变更偏向才会触发批量重偏向。
参考资料:【黑马程序员深入学习Java并发编程,JUC并发编程全套教程-哔哩哔哩】 https://b23.tv/dt4w9la