sychronized实现原理

来源:互联网 发布:java上机编程题面试 编辑:程序博客网 时间:2024/06/05 17:04

测试类:


打开cmd,执行javac  java文件的路径进行编译该文件,生成.class文件,然后执行javap -c生成的.class文件反编译.class文件,-c表示打印出方法的字节码指令,结果如下


发现有俩个监视类的东西,monitorenter,monitorexit,在线查看jvm规范,描述如下


大致翻译就是

monitorenter 获取由objectref引用的对象的排他锁有三种可能的情况:

如果没有其他线程锁定对象,则在对象上建立一个新的锁,并在下一条指令继续执行。

如果对象当前被另一个线程锁定,monitorenter 阻塞,等待另一个线程解锁对象。

如果当前线程已经拥有对象上的锁定,则计数器将递增 - 只有在计数器返回零时才会释放该锁定(见monitorexit)。

所述monitorenter / monitorexit机构用于由Java 同步语句来协调访问多个线程之间的对象。


大致翻译就是

monitorexit 释放了以前使用 monitorenter获取的对象objectref的独占锁如果其他线程正在等待对象解锁,其中一个等待线程将能够获取对象上的锁并继续。

请注意,单个线程可以多次锁定对象 - 运行时系统维护对象被当前线程锁定的次数的计数,并且仅当计数器达到零时解锁对象(即,当monitorenters的数量并且应用于给定对象的monitorexits是相等的)。

 意思就是,执行monitorexit指令的线程必须是已经拥有该monitor的线程,执行monitorexit指令后,该monitor的进入数减1,直到该monitor的进入数为0,此时该线程不再是改monitor的所有者,其他被阻塞进入该monitor的线程可以尝试获取该monitor的所有权。


以上就是sychronized的实现原理,后面还特别提示了


也就是说wait,notify,notifyAll也是基于monitor对象实现的,这就是为什么只有在同步块中才能使用wait/notify/notifyAll方法

那么来实验sychronized同步方法


用 javap -verbose命令反编译如上程序,-verbose查看类加载情况,结果如下


可以看到他有一个ACC_SYNCHRONIZED标志,jvm就是通过该标志来判断是否需要实现同步,具体过程为:当线程执行该方法时,会检查该方法是否标志了ACC_SYNCHRONIZED,如果标志了,线程需要先获取monitor,获取成功后才能调用方法,方法执行完后再释放monitor,在该线程调用方法期间,其他线程无法获取同一个monitor对象。其实本质上和sychronized块相同,只是同步方法是用一种隐式的方式来实现,而不是显示的通过字节码指令。

参考:http://blog.csdn.net/xiangwanpeng

0 0
原创粉丝点击