重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要讲解了“Java中synchronized的作用及用法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中synchronized的作用及用法”吧!
目前创新互联已为成百上千家的企业提供了网站建设、域名、虚拟空间、网站托管、企业网站设计、清镇网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
synchronized是属于JVM层面的一个关键字,底层是通过一个monitor对象(管程对象)来完成,由于wait()/notify()等方法也依赖于monitor对象,所以只有在同步的块或者方法中才能调用wait/notify等方法
synchronized同步语句块的实现使用monitorenter和 monitorexit指令。
monitorenter:指令指向同步代码块的开始位置
monitorexit:指令则指明同步代码块的结束位置
当执行monitorenter指令时,当前线程将试图获取 objectref(即对象锁) 所对应的 monitor的持有权,当 objectref的monitor 的进入计数器**为0,那线程可以成功取得 monitor,并将计数器值设置为 1,取锁成功。
如果当前线程已经拥有 objectref 的 monitor 的持有权,那它可以重入这个 monitor (关于重入性稍后会分析),重入时计数器的值也会加 1。
倘若其他线程已经拥有objectref 的 monitor 的所有权,那当前线程将被阻塞,直到正在执行线程执行完毕,即monitorexit指令被执行,执行线程将释放monitor(锁)并设置计数器值为0,其他线程将有机会持有 monitor ;**
为了保证在方法异常完成时 monitorenter 和 monitorexit 指令依然可以正确配对执行,编译器会自动产生一个异常处理器,这个异常处理器声明可处理所有的异常,它的目的就是用来执行 monitorexit 指令。
从字节码中也可以看出多了一个monitorexit指令,它就是异常结束时被执行的释放monitor的指令;
每个对象有一个管程对象(monitor),当monitor被占用时就会处于锁定状态;线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:
如果monitor的进入计数器为0,则该线程进入monitor,然后将进入计数器设置为1,该线程即为monitor的所有者;
如果线程已经之前占用了该monitor,本次只是重新进入,则将monitor的进入计数器加1;
如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入计数器为0,再重新尝试获取monitor的所有权;
执行monitorexit的线程必须是objectref(即对象锁)所对应的monitor的所有者;
指令执行时,monitor的进入计数器减1,如果减1后进入计数器为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权.
方法级的同步是隐式,即无需通过字节码指令(monitorenter和monitorexit)来控制的。 它实现在方法调用和返回操作之中。
JVM可以从方法常量池中的方法表结构(method_info Structure) 中的ACC_SYNCHRONIZED访问标志区分一个方法是否同步方法。
当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程将先持有monitor(虚拟机规范中用的是管程一词)。
然后再执行方法,最后在方法完成(无论是正常完成还是非正常完成)时释放monitor。
在方法执行期间,执行线程持有了monitor,其他任何线程都无法再获得同一个monitor。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的monitor将在异常抛到同步方法之外时自动释放。
感谢各位的阅读,以上就是“Java中synchronized的作用及用法”的内容了,经过本文的学习后,相信大家对Java中synchronized的作用及用法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!