Synchronized偏向锁批量重偏向与批量撤销
1.批量重偏向
intx BiasedLockingBulkRebiasThreshold = 20 默认偏向锁批量重偏向阈值
可以通过JVM参数 -XX:BiasedLockingBulkRebiasThreshold手动设置阈值
起因:
当一个线程A对某个类生成大量的对象的对象,这些对象偏向了A,后面突然有来了个线程B去抢线程A生成的对象,就会导致偏向锁的升级为轻量级锁,如果总是在不断的升级锁,到了一定的阈值,JVM 就会对类的所有对象进行批量的重新偏向与B。
测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50public class BiasedLock {
public static void main(String[] args) throws InterruptedException {
//偏向延时
Thread.sleep(5000);
final ArrayList<Dog> dogArrayList = new ArrayList<>();
Runnable runnable1 = new Runnable() {
public void run() {
while (dogArrayList.size() < 60) {
Dog dog = new Dog();
synchronized (dog){
dogArrayList.add(dog);
HeaderPrint.parseHeaderInfo(dog);
}
}
//保持线程不要退出
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable runnable2 = new Runnable() {
public void run() {
for (int i = 0; i < 50; i++) {
Dog dog = dogArrayList.get(i);
synchronized (dog){
System.out.print((i+1)+":");
dogArrayList.add(dog);
HeaderPrint.parseHeaderInfo(dog);
}
}
//保持线程不要退出
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
new Thread(runnable1).start();
//保证线程1生成完毕
Thread.sleep(5000);
new Thread(runnable2).start();
}
}我们可以看到,线程2启动的时候,是从偏向锁升级到了 轻量级锁
一直升级到 阈值20的时候,触发JVM优化机制,JVM认为偏向的不对,怎么总是线程2来强=抢,总的升级锁,比较麻烦,所以JVM直接让剩下dog对象,直接重新偏向到线程2
线程0 的偏向值 thread:54:000000000000000001111111101001001000101100000011000100(HEX:1fe922c0c4)
在 第 20个是的时候,就已经重新偏向了
后面的也都是偏向锁
1
2
3
4
5
6
7
8
9
10
50:
--------START-----------Thread-2
--------偏向锁--------
thread:54:000000000000000001111111101001001000101100011000001110(HEX:1fe922c60e)
epoch:2:01
unused:1:0
age:4:0000
biased_lock:1:1
--------END-----------Thread-22.批量撤销
intx BiasedLockingBulkRevokeThreshold = 40 默认偏向锁批量撤销阈值
可以通过JVM参数 -XX:BiasedLockingBulkRevokeThreshold手动设置阈值
起因:
在多个线程竞争剧烈的情况下,使用偏向锁将会降低效率,于是乎产生了批量撤销机制。
测试代码:
批量重偏向和批量撤销是针对类的优化。
偏向锁只会重偏向一次,后面就是升级锁
当某个类已经触发批量撤销机制后,该类的对象不会再使用偏向锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82public static void main(String[] args) throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(2);
//偏向延时
Thread.sleep(5000);
final ArrayList<Dog> dogArrayList = new ArrayList<>();
Runnable runnable1 = new Runnable() {
public void run() {
while (dogArrayList.size() < 80) {
Dog dog = new Dog();
synchronized (dog) {
dogArrayList.add(dog);
}
}
//保持线程不要退出
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable runnable2 = new Runnable() {
public void run() {
for (int i = 0; i <39; i++) {
if (i == 38) {
System.out.println((i + 1) + ":");
//这里主要是给主线程留出时间,让主线程打印出一个new Dog
countDownLatch.countDown();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Dog dog = dogArrayList.get(i);
synchronized (dog) {
dogArrayList.add(dog);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//保持线程不要退出
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
new Thread(runnable1).start();
//保证线程1生成完毕
Thread.sleep(3000);
//重新偏向线程2
new Thread(runnable2).start();
Thread.sleep(3000);
//线程3导致偏向锁升级
new Thread(runnable2).start();
//线程3导致锁升级到39的时候,new出来的对象,默认是可偏向的状态
countDownLatch.await();
HeaderPrint.parseHeaderInfo(new Dog());
//保证之后
Thread.sleep(3000);
//第39之后的新对象,已经没有偏向了,偏向被撤销了
HeaderPrint.parseHeaderInfo(new Dog());
}输出
第39的时候,默认输出的是,可偏向状态
第39之后,new 的对象,已经被取消默认可偏向的状态了,成无锁了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2039:
--------START-----------main
--------偏向锁--------
thread:54:000000000000000000000000000000000000000000000000000000(HEX:0)
epoch:2:01
unused:1:0
age:4:0000
biased_lock:1:1
--------END-----------main
--------START-----------main
--------无锁-----------
unused:25:0000000000000000000000000
identity_hashcode:31: 0000000000000000000000000000000 (Hex:0)
unused:1:0
age:4:0000
biased_lock:1:0
lock:2:01
--------END-----------main