synchronized、monitor、wait、notify

Synchronize是java中解决并发问题比较常用的一种方法。从语法上面来说synchronized总共有三种用法。修饰普通方法,修饰静态方法,和同步代码块。

我们对同步代码块的方法进行反编译,可以发现,在synchronized囊括的代码中分别有monitorenter和monitorexit两个指令。虚拟机规范中对着两个指令如下描述:每个对象都有一个monitor。当monitor被占用的时候就会处于锁定状态。当线程monitorenter指令尝试获取monitor所有权时,如果进入数为0,则该线程进入,将进入数设置为1,该线程几位monitor的所有者。其他的线程在进入的时候就会进入阻塞状态,知道monitor的进入数量为0.而monitorexit会对进入数量减1,当变为0的时候,monitor就不再被这个线程占用。

而对synchronize修饰的方法反编译的时候发现,方法没有在使用monitorenter和monitorexit来实现,但是在方法的flags中acc——synchronized的标志。当调用acc_synchronize标志的方法的时候也会先去获取monitor对象,所以本质上和同步代码块是一样的。

同步代码块的monitor来自指定对象,同步方法来自当前实例,而静态方法来自class对象。

在java中每个对象都有monitor。对象在内存中的布局可以分为3个区块,对象头,实例数据和对齐填充。其中对象头保存了锁状态标识,线程持有锁等相关的数据。

而对象的wait和notify的方法也是通过monitor来实现的,一个持有对象线程通过调用对象的wait方法,释放该对象的monitor并且进入休眠,其他的线程通过对象对的notify和notifyall再次获取monitor。所以wait和notify都需要持有对象的monitor才能调用,否则将抛出IllegalMonitorStateException。这也是wait和notify需要在同步的方法中的原因。

posted @ 2017-08-19 11:49  依米熊  阅读(1217)  评论(0编辑  收藏  举报