Synchronized的作用方式:
- 作用于代码块
- 作用于实例方法
- 作用于静态方法
- 作用于对象
1. 同步代码块和同步实例方法的区别:只有进入同步代码块才会锁住对象,而进入同步方法立即锁住对象。
public void print(){ System.out.print("进入方法+线程:" + Thread.currentThread.getName()); Synchronized(obj){ while(true){} } } public synchronized void print(){ System.out.print("进入方法+线程:" + Thread.currentThread.getName()); while(true){} }
线程A,B分别同时执行两个print()方法的结果:
进入方法+线程1 进入方法+线程2 =================== 进入方法+线程1
2. 同步实例方法锁住对象,同步静态方法和同步类一样锁住class对象
3.JVM内部实现
对于同步代码块:需要jvm和编译器配合实现。JVM指令集中有monitorenter和monitorexit指令支持synchronized关键字,monitorenter插入到同步代码块开始的地方,monitorexit插入到同步代码块结束的地方,编译器保证每一条monitorenter指令都必须执行对应的monitorexit指令,为了保证方法异常完成时,monitorenter和monitorexit依然正确配对执行,编译器自动产生一个异常处理器,这个异常处理器处理所有异常,目的就是用来执行monitorexit指令。任何对象都有一个monitor与之关联,monitor内部有一个owner字段,初始为null,保存持有该monitor的线程唯一标识。当进入同步时,线程都要尝试获取monitor。
对于同步方法:无需通过字节码指令控制,实现在方法调用和返回的操作中。JVM从方法常量池的方法表结构中的ACC_SYNCHRONIZED访问标志得知一个方法是否声明为同步方法。当方法调用时,调用指令会检查方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程就要求先成功持有管程,然后才能执行方法,当方法退出(正常/抛出异常)时,释放管程。
参考:
https://www.zhihu.com/question/57794716?sort=created
https://www.jianshu.com/p/4e4c67d7ad4a
https://www.jianshu.com/p/d99993b52a07