synchronized
sychronized代码块如何保证加锁解锁的成对出现?
对如下这样一个简单的代码用javap查看的bytecode信息
public class public class Demo {
public static void main(String[] args) {
Object lock = new Object();
synchronized (lock) {
System.out.println("ok");
}
}
}
javac -g Demo.java
javap -v Demo
public static void mainpublic static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
-------- 0 ~ 7 为 Object lock = new Object()对 应的bytecode -----
//new在堆中产生新的对象的同时,将对象的一个引用放入操作数栈
0: new #2 // new Object
//dup复制一份对象的引用,是为了用2次
3: dup
//执行invokespecial指令,消耗栈顶的一个对象的引用,调用构造方法
4: invokespecial #1
7: astore_1 //第二个lock引用赋给局部变量表中1号slot的name为lock的局部变量
8: aload_1 //将对象引用加载到操作数栈
9: dup //再复制一份,分别给monitorenter,monitorexit使用,分别为加锁和解锁
10: astore_2 //将刚才新产生的对象引用 存储到2号slot(没有名字的slot)
11: monitorenter //还剩的一个对象引用被monitorenter消耗掉,这就是加锁操作
-------- 12 ~ 21 为sychronized代码块内部-----
12: getstatic #3 // < - System.out
15: ldc #4 // < = "ok"
17: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: aload_2 //将刚才存到slot_2的对象引用加载到操作数栈给解锁指令用
21: monitorexit
22: goto 30
//怎样保证一定会解锁?利用异常表
25: astore_3 // 将异常对象的引用存到slot_3
26: aload_2 // < - slot_2(lock引用)
27: monitorexit // monitorexit(lock引用),确保对同一个对象解锁
28: aload_3 //刚才的异常对象引用加载进来,进行抛出
29: athrow
30: return
Exception table:
from to target type
12 22 25 any
25 28 25 any
LocalVariableTable:
Start Length Slot Name Signature
0 31 0 args [Ljava/lang/String;
8 23 1 lock Ljava/lang/Object;
总结:
1.sychronized
用于对象上时,会产生2份对象的引用,分别给加锁和解锁指令用
2.sychronized
用于对象上时,利用异常表,不管sychronized
中的代码是否正常执行,都将会对同一个对象解锁
重量级锁
轻量级锁
提升同步性能的依据是:对于绝大部分的锁,在整个同步周期内都是不存在竞争的。
轻量级锁使用CAS操作避免了使用重量级锁(互斥量)的开销。
加锁过程
建立锁记录,存储Mark Word
如果此同步对象没有被锁定(锁标志位为01),虚拟机首先在当前线程栈帧中建立一个锁记录的空间,用于存储锁对象当前的Mark Word的拷贝
使用CAS将Mark Word指向锁记录
- 操作成功,进入轻量级锁定状态,锁标志改为00
- CAS操作失败,检查对象的Mark Word是否指向当前线程的栈帧
- 是,进入同步块继续执行(锁重入)
- 否,说明这个锁对象被其他线程抢占了,锁膨胀为重量级锁(锁标志位为10),自己进入阻塞状态。
锁对象:门。
重量级锁:防盗锁。
轻量级锁:书包(不同人书包是一样的,里面的书本不一样)
偏向锁:写名字
偏向锁
1.是JDK1.6种引入的一项锁优化
2.它的目的是消除数据在有同步无竞争情况下的同步原语,进一步提高程序的运行性能。
3.如果说轻量级所是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了。
开始是偏向锁,有其他线程来时,竞争发生,升级为轻量级锁。
竞争存在,但竞争的程度轻,自旋即等待 一会儿,另1个线程就胡释放锁。
自旋超过一定次数,轻量级锁升级为重量级所。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!