Java并发
synchronized 的一些学习记录
jdk1.6 以后对 synchronized 进行了一些优化,包括偏向锁,轻量级锁,重量级锁等
这些锁的加锁方式大多跟对象头有关,我们可以查看 jdk 代码
首先对象头的位置注释
enum { locked_value = 0,
unlocked_value = 1,
monitor_value = 2,
marked_value = 3,
biased_lock_pattern = 5
};
我们可以用 java jol库来查看对象头,通过一段简单的代码来看下
public class ObjectHeaderDemo {
public static void main(String[] args) throws InterruptedException {
L l = new L();
System.out.println(ClassLayout.parseInstance(l).toPrintable());
}
}
![Untitled]()
然后可以看到打印输出,当然这里因为对齐方式,我们看到的其实顺序是反过来的,按最后三位去看,我们这是 001,好像偏向锁都没开,这里使用的是 jdk1.8,默认开始偏向锁的,其实这里有涉及到了一个配置,jdk1.8 中偏向锁会延迟 4 秒开启,可以通过添加启动参数 -XX:+PrintFlagsFinal,看到
![偏向锁延迟]()
因为在初始化的时候防止线程竞争有大量的偏向锁撤销升级,所以会延迟 4s 开启
我们再来延迟 5s 看看
public class ObjectHeaderDemo {
public static void main(String[] args) throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
L l = new L();
System.out.println(ClassLayout.parseInstance(l).toPrintable());
}
}
![https://img.nicksxs.com/uPic/2LBKpX.jpg]()
可以看到偏向锁设置已经开启了,我们来是一下加个偏向锁
public class ObjectHeaderDemo {
public static void main(String[] args) throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
L l = new L();
System.out.println(ClassLayout.parseInstance(l).toPrintable());
synchronized (l) {
System.out.println("1\n" + ClassLayout.parseInstance(l).toPrintable());
}
synchronized (l) {
System.out.println("2\n" + ClassLayout.parseInstance(l).toPrintable());
}
}
}
看下运行结果
![https://img.nicksxs.com/uPic/V2l78m.png]()
可以看到是加上了 101 = 5 也就是偏向锁,后面是线程 id
当我再使用一个线程来竞争这个锁的时候
public class ObjectHeaderDemo {
public static void main(String[] args) throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
L l = new L();
System.out.println(ClassLayout.parseInstance(l).toPrintable());
synchronized (l) {
System.out.println("1\n" + ClassLayout.parseInstance(l).toPrintable());
}
Thread thread1 = new Thread() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(5L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (l) {
System.out.println("thread1 获取锁成功");
System.out.println(ClassLayout.parseInstance(l).toPrintable());
try {
TimeUnit.SECONDS.sleep(5L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread1.start();
}
}
![https://img.nicksxs.com/uPic/bRMvlR.png]()
可以看到变成了轻量级锁,在线程没有争抢,只是进行了切换,就会使用轻量级锁,当两个线程在竞争了,就又会升级成重量级锁
public class ObjectHeaderDemo {
public static void main(String[] args) throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
L l = new L();
System.out.println(ClassLayout.parseInstance(l).toPrintable());
synchronized (l) {
System.out.println("1\n" + ClassLayout.parseInstance(l).toPrintable());
}
Thread thread1 = new Thread() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(5L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (l) {
System.out.println("thread1 获取锁成功");
System.out.println(ClassLayout.parseInstance(l).toPrintable());
try {
TimeUnit.SECONDS.sleep(5L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(5L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (l) {
System.out.println("thread2 获取锁成功");
System.out.println(ClassLayout.parseInstance(l).toPrintable());
}
}
};
thread1.start();
thread2.start();
}
}
class L {
private boolean myboolean = true;
}
![https://img.nicksxs.com/uPic/LMzMtR.png]()
可以看到变成了重量级锁。