面试必问的Synchronized知道这些就可以了
Synchronized关键字算是Java的元老级锁了,一开始它撑起了Java的同步任务,其用法简单粗暴容易上手。但是有些与它相关的知识点还是需要我们开发者去深入掌握的。比如,我们都知道通过Synchronized锁来实现互斥功能,可以用在方法或者代码块上,那么不同用法都是怎么实现的,以及都经历了了哪些优化等等问题都需要我们扎实的理解。
对于普通同步方法,锁是当前实例对象,也就是this
public class TestSyn{ private int i=0; public synchronized void incr(){ i++; } }
对于静态同步方法,锁是Class对象
public class TestSyn{ private static int i=0; public static synchronized void incr(){ i++; } }
对于同步代码块,锁是同步代码块里的对象
public class TestSyn{ private int i=0; Object o = new Object(); public void incr(){ synchronized(o){ i++; } } }
2.实现原理
在JVM规范中介绍了synchronized的实现原理,JVM基于进入和退出Monitor对
象来实现方法同步和代码块同步,但两者的实现细节不一样。代码块同步是使用monitorenter和monitorexit指令实现的,而方法同步是使用另外一种方式实现的,通过一个方法标志(flag) ACC_SYNCHRONIZED来实现的。2.1 同步代码块的实现
monitorenter 和 monitorexit
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.monitorenter (参考来源)
下面看下JVM规范里对moniterenter 和 monitorexit的介绍
Each object has a monitor associated with it. The thread that executes monitorenter gains ownership of the monitor associated with objectref. If another thread already owns the monitor associated with objectref, the current thread waits until the object is unlocked,
每个对象都有一个监视器(Moniter)与它相关联,执行moniterenter指令的线程将获得与objectref关联的监视器的所有权,如果另一个线程已经拥有与objectref关联的监视器,则当前线程将等待直到对象被解锁为止。
A monitorenter instruction may be used with one or more monitorexit instructions to implement a synchronized statement in the Java programming language. The monitorenter and monitorexit instructions are not used in the implementation of synchronized methods
重点来了,上面这段介绍了两点:
- 通过monitorenter和monitorexit指令来实现Java语言的同步代码块(后面有代码示例)
- monitorenter和monitorexit指令没有被用在同步方法上!!!
A synchronized method is not normally implemented using monitorenter and monitorexit. Rather, it is simply distinguished in the runtime constant pool by the ACC_SYNCHRONIZED flag, which is checked by the method invocation instructions. When invoking a method for which ACC_SYNCHRONIZED is set, the current thread acquires a monitor, invokes the method itself, and releases the monitor whether the method invocation completes normally or abruptly.
上面这段话主要讲了几点:
- 同步方法的实现不是基于monitorenter和monitorexit指令来实现的
- 在运行时常量池里通过ACC_SYNCHRONIZED来区分是否是同步方法,方法执行时会检查该标志
- 当一个方法有这个标志的时候,进入的线程首先需要获得监视器才能执行该方法
- 方法结束或者抛异常时会释放监视器