java 锁 关键字_Java锁synchronized关键字原理的Mark Word理解

synchronized是Java里锁使用的关键字,而synchronized的底层jvm实现是依赖一个交monitor的对象。monitor管理锁的持有者的进入和退出。

当synchronized用来修饰同步代码块时,这时是由monitorenter和monitorexit指令来控制同步的。

2b140f1af5143645e6386c89eaa5f94a.png

有下面这段代码

public class SyncCodeBlock {

public int i;

public void syncTask(){

//同步代码库

synchronized (this){

i++;

}

}

}

1

2

3

4

5

6

7

8

9

10

11

publicclassSyncCodeBlock{

publicinti;

publicvoidsyncTask(){

//同步代码库

synchronized(this){

i++;

}

}

}

利用jdk自带的javap命令进行解析字节码文件

Last modified 2017-6-2; size 426 bytes

MD5 checksum c80bc322c87b312de760942820b4fed5

Compiled from "SyncCodeBlock.java"

public class com.zejian.concurrencys.SyncCodeBlock

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

//........省略常量池中数据

//构造函数

public com.zejian.concurrencys.SyncCodeBlock();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=1, locals=1, args_size=1

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: return

LineNumberTable:

line 7: 0

//===========主要看看syncTask方法实现================

public void syncTask();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=3, locals=3, args_size=1

0: aload_0

1: dup

2: astore_1

3: monitorenter //注意此处,进入同步方法

4: aload_0

5: dup

6: getfield #2 // Field i:I

9: iconst_1

10: iadd

11: putfield #2 // Field i:I

14: aload_1

15: monitorexit //注意此处,退出同步方法

16: goto 24

19: astore_2

20: aload_1

21: monitorexit //注意此处,退出同步方法

22: aload_2

23: athrow

24: return

Exception table:

//省略其他字节码.......

}

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

Lastmodified2017-6-2;size426bytes

MD5checksumc80bc322c87b312de760942820b4fed5

Compiledfrom"SyncCodeBlock.java"

publicclasscom.zejian.concurrencys.SyncCodeBlock

minorversion:0

majorversion:52

flags:ACC_PUBLIC,ACC_SUPER

Constantpool:

//........省略常量池中数据

//构造函数

publiccom.zejian.concurrencys.SyncCodeBlock();

descriptor:()V

flags:ACC_PUBLIC

Code:

stack=1,locals=1,args_size=1

0:aload_0

1:invokespecial#1                  // Method java/lang/Object."":()V

4:return

LineNumberTable:

line7:0

//===========主要看看syncTask方法实现================

publicvoidsyncTask();

descriptor:()V

flags:ACC_PUBLIC

Code:

stack=3,locals=3,args_size=1

0:aload_0

1:dup

2:astore_1

3:monitorenter//注意此处,进入同步方法

4:aload_0

5:dup

6:getfield#2             // Field i:I

9:iconst_1

10:iadd

11:putfield#2            // Field i:I

14:aload_1

15:monitorexit//注意此处,退出同步方法

16:goto24

19:astore_2

20:aload_1

21:monitorexit//注意此处,退出同步方法

22:aload_2

23:athrow

24:return

Exceptiontable:

//省略其他字节码.......

}

其中主要关注如下信息

3: monitorenter //进入同步方法

//..........省略其他

15: monitorexit //退出同步方法

16: goto 24

//省略其他.......

21: monitorexit //退出同步方法

1

2

3

4

5

6

3:monitorenter//进入同步方法

//..........省略其他

15:monitorexit//退出同步方法

16:goto24

//省略其他.......

21:monitorexit//退出同步方法

其中monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置。

当执行monitorenter指令时,当前线程将试图获取 objectref(即对象锁) 所对应的 monitor 的持有权,当 objectref 的 monitor 的进入计数器为 0,那线程可以成功取得 monitor,并将计数器值设置为 1,取锁成功。

如果当前线程已经拥有 objectref 的 monitor 的持有权,那它可以重入这个 monitor (关于重入性稍后会分析),重入时计数器的值也会加 1。

倘若其他线程已经拥有 objectref 的 monitor 的所有权,那当前线程将被阻塞,直到正在执行线程执行完毕,即monitorexit指令被执行,执行线程将释放 monitor(锁)并设置计数器值为0 ,其他线程将有机会持有 monitor 。

值得注意的是编译器将会确保无论方法通过何种方式完成,方法中调用过的每条 monitorenter 指令都有执行其对应 monitorexit 指令,而无论这个方法是正常结束还是异常结束。为了保证在方法异常完成时 monitorenter 和 monitorexit 指令依然可以正确配对执行,编译器会自动产生一个异常处理器,这个异常处理器声明可处理所有的异常,它的目的就是用来执行 monitorexit 指令。

从字节码中也可以看出多了一个monitorexit指令,它就是异常结束时被执行的释放monitor 的指令。

浏览量:

40

0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值