查看http://hg.openjdk.java.net/jdk8u/jdk8u60/hotspot/file/37240c1019fd/src/share/vm/oops/markOop.hpp
biased object注释看得出偏向锁存储的为线程信息。
配置参数查看jvm初始批量重偏向与批量撤销的阈值:
误区:有时候你发现没有超过阈值发生重偏向:
引入:
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
package sync;
import org.openjdk.jol.info.ClassLayout;
import java.util.ArrayList;
import java.util.List;
public class SyncExplore2 {
static Thread t1;
static Thread t2;
public static void main(String[] args) {
try {
Thread.sleep(5000);
final List<DouFuDan> list = new ArrayList<DouFuDan>();
t1 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
DouFuDan douFuDan = new DouFuDan();
synchronized (douFuDan) {
if (i == 1) {
System.out.println("t1 locking");
System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
}
list.add(douFuDan);
}
}
}
};
t1.start();
Thread.sleep(3000);
t2 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
DouFuDan douFuDan = list.get(i);
synchronized (douFuDan) {
if (i == 2 || i == 3 || i == 4) {
System.out.println("t2 locking");
System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
}
}
}
}
};
t2.start();
}catch (Exception e) {
e.printStackTrace();
}
}
}
你会发现:
没到达到阈值没有变为轻量级锁,但是仔细一看存储的线程id一样的,哦,原来并没有重偏向线程2,怀疑:jvm可能让t2复用了t1的线程id,导致认为线程1没有挂掉,还保持偏向。
批量重偏向:
package sync;
import org.openjdk.jol.info.ClassLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;
/**
* 批量重偏向
*/
public class SyncExplore1 {
static Thread t1;
static Thread t2;
public static void main(String[] args) {
try {
Thread.sleep(5000);
final List<DouFuDan> list = new ArrayList<DouFuDan>();
t1 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
DouFuDan douFuDan = new DouFuDan();
synchronized (douFuDan) {
if (i == 2) {
System.out.println("t1 locking");
System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
}
list.add(douFuDan);
}
}
LockSupport.unpark(t2);
}
};
t1.start();
t2 = new Thread() {
@Override
public void run() {
LockSupport.park();
for (int i = 0; i < 20; i++) {
DouFuDan douFuDan = list.get(i);
synchronized (douFuDan) {
if (i == 19) {
System.out.println("t2 locking");
System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
}
}
}
}
};
t2.start();
}catch (Exception e) {
e.printStackTrace();
}
}
}
两个偏向锁的线程信息不一样,当对一个对象进行偏量锁撤销为无锁再变成轻量锁时epoch计数进行加一,当加到阈值20时,epoch的2个bit标识变为10,这时候jvm认为Class偏向锁出现了问题,会重新添加偏向锁。
批量撤销:
package sync;
import org.openjdk.jol.info.ClassLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;
/**
* 批量撤销
*/
public class SyncExplore {
static Thread t1;
static Thread t2;
static Thread t3;
public static void main(String[] args) {
try {
Thread.sleep(5000);
final List<DouFuDan> list = new ArrayList<DouFuDan>();
t1 = new Thread() {
@Override
public void run() {
for (int i=0;i<100;i++) {
DouFuDan douFuDan = new DouFuDan();
synchronized (douFuDan) {
if(i==0) {
System.out.println("t1 locking");
System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
}
list.add(douFuDan);
}
}
LockSupport.unpark(t2);
}
};
t1.start();
t2 = new Thread() {
@Override
public void run() {
LockSupport.park();
for (int i=0;i<list.size();i++) {
DouFuDan douFuDan = list.get(i);
synchronized (douFuDan) {
if(i == 19) {
System.out.println("t2 locking");
System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
}
}
}
LockSupport.unpark(t3);
}
};
t2.start();
t3 = new Thread() {
@Override
public void run() {
LockSupport.park();
for (int i=20;i<list.size();i++) {
DouFuDan douFuDan = list.get(i);
synchronized (douFuDan) {
if(i == 40) {
System.out.println("t3 locking");
System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
}
}
}
}
};
t3.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
发现到达40阈值的时候,锁变为了轻量级锁,epoch计数加到40,epoch标志位变为01,可能是jvm认为存在线程竞争,标记为不可偏向,直接升级为轻量级锁。