Java并发编程- Synchronized原理
在jdk.1.6之前是重量级锁,jdk1.6之后对synchronzied的关键字的优化之后,引入了偏向锁,轻量级锁。
1.先来看synchronzied使用的基础:
static A a = new A();
//普通同步方法
public synchronized void test(){
System.out.println("锁的是当前对象实例");
}
//静态同步方法
public static synchronized void test1(){
System.out.println("锁的是当前类的Class对象");
}
//同步方法块
public void test2(){
synchronized (a){
System.out.println("锁的是括号里配置的对象");
}
}
2. synchronzied使用的锁在哪呢?存在对象头里,
整个对象存储情况,运行代码查看结果分析:
public class A {
private boolean b;
}
public class Test {
static A a = new A();
public static void main(String[] args) {
System.out.println(VM.current().details());
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
运行结果分析:
分析:对象一共16B,其中12B是对象头,1B是对象实例数据,3B是字节对齐
对象的长度
长度 | 内容 | 说明 |
12B | 对象头 | 存储信息,hashcode,年代信息等。 |
1B | 对象实例数据 | 存储对象的实例数据 |
3B | 字节对齐 |
对象头12B存储哪些内容呢?64位的VM
可以从openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html 官网上看到,存储的内容是mark word 和klass word
java对象头的长度
长度 | 内容 | 说明 |
8B | mark word | 存储着锁的信息,hashcode,gc信息等等 |
4B | klass word | 指向对象的元数据 |
java对象头的结构
无锁的对象头如下:
第一个字节的前8位存储着,分代年龄4个bit,锁的标识2个bit,是否偏向1个bit,和没有使用的1个bit。
其他的7个字节存储着hashcode信息。
锁状态 | 56bit | 4bit | 1bit是否偏向锁 | 2bit锁的标识 |
无锁 | 对象hashcode | 对象分代年龄 | 0 | 01 |
我们知道对象的状态一共五种状态:无锁,偏向锁,轻量级锁,重量级锁,gc标记的锁。
3. 偏向锁
概念:同一个线程多次获取同一把锁。(只有一个线程调用同步块)
代码:
public class Test {
static A a ;
public static void main(String[] args) {
Thread.sleep(5000);//jvm 延时启动偏向锁,是默认4s之后开启,可以设置关闭延时。因为启动的时候就使用偏向锁,比较消耗性能,升级锁比较费时间。
System.out.println(VM.current().details());
a = new A();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
syn();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
public static synchronized void syn(){
System.out.println("演示偏向锁-----------");
}
}
输出结果:
演示偏向锁-----------
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 80 22 01 f8 (10000000 00100010 00000001 11111000) (-134143360)
12 1 boolean A.b false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
分析结果:程序只有一个线程main调用syn方法,因此是偏向锁,也可以使用-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0禁用延时。-XX:+TraceClassLoading (跟踪加载)
4. 轻量级锁:线程交替运行,无竞争。
public class Test {
static A a ;
public static void main(String[] args) throws InterruptedException {
// System.out.println(VM.current().details());
a = new A();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
syn();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
public static void syn(){
synchronized (a){
out.println("lock ing");
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
}
运行结果:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 1 boolean A.b false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
lock ing
com.luban.wf.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) a0 f5 e7 02 (10100000 11110101 11100111 00000010) (48756128)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 1 boolean A.b false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
com.luban.wf.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 1 boolean A.b false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
Process finished with exit code 0
分析结果:lock ing 输出的10100000 轻量级锁。
5. 重量级锁:
public class Test2 {
static A a ;
public static void main(String[] args) throws InterruptedException {
a = new A();
System.out.println("before lock");
out.println(ClassLayout.parseInstance(a).toPrintable());//轻量锁
Thread t1 = new Thread(new Runnable() {
public void run() {
synchronized (a){
synchronized (a){
System.out.println("before wait");
out.println(ClassLayout.parseInstance(a).toPrintable());//轻量锁
try {
a.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after wait");
out.println(ClassLayout.parseInstance(a).toPrintable());//重量级锁
}
}
}
});
t1.start();
Thread.sleep(5000);
synchronized (a){
a.notifyAll();//唤醒线程t1
}
}
}
运行结果:
before lock
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 1 boolean A.b false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
before wait
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) a0 f2 7b 1c (10100000 11110010 01111011 00011100) (477885088)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 1 boolean A.b false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
after wait
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) da d7 e2 19 (11011010 11010111 11100010 00011001) (434296794)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 1 boolean A.b false
13 3 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
Process finished with exit code 0
运行结果分析:after wait 的为11011010 重量级锁
6. 偏向锁的批量撤销:
7. 轻量级锁的膨胀过程:
8.总结:
锁有哪几种:公平锁和非公平锁(线程获取锁的机会不是均匀的)
工作当中怎样选择锁:
Synchronized 是有sun公司实现的 jvm内部调用操作系统实现的
1.是个非公平锁,
2.使用简单,
3.经过优化了,偏向锁,轻量级锁,重量级锁
lock jdk实现的:
1.是个公平锁,
2.需要手动释放锁
3.如果要实现高级功能,可以使用