赞
踩
jvm基于进入和退出Monitor对象来实现方法同步和代码块同步,其中方法同步是使用ACC_SYNCHRONIZED 、代码块同步是使用monitorenter、monitorexit指令
对应的代码和反编译代码如下,使用javap -v xxx.class进行反编译
public class SynchronizedTest { public void get(){ synchronized (this){ // 这个是同步代码块 System.out.println("你好呀"); } } public synchronized void f(){ //这个是同步方法 System.out.println("Hello world"); } public static synchronized void f2(){ //这个是同步方法 System.out.println("Hello world"); } public static void main(String[] args) { } }
它的底层是通过monitorenter、monitorexit指令来实现的。
monitorenter:
每个对象都是一个监视器锁(monitor),当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。**如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1。**如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。
monitorexit:
**执行monitorexit的线程必须是object所对应的monitor持有者。**指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个monitor的所有权。
monitorexit指令出现了两次,第1次为同步正常退出释放锁;第2次为发生异步退出释放锁
代码中的f和f2方法对应反编译中代码如下图:
方法的同步并没有通过 monitorenter 和 monitorexit 指令来完成,不过相对于普通方法,其常量池中多了 ACC_SYNCHRONIZED 标示符。JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。归根结底还是对monitor对象的争夺,只是同步方法是一种隐式的方式来实现。
参考答案
synchronized可以修饰静态方法,但不能修饰静态代码块。
当修饰静态方法时,监视器锁(monitor)便是对象的Class实例,因为Class数据存在于永久代,因此
静态方法锁相当于该类的一个全局锁。
synchronized
关键字的使用方式主要有下面 3 种:
1、修饰实例方法 (锁当前对象实例)
给当前对象实例加锁,进入同步代码前要获得 当前对象实例的锁 。
synchronized void method() {
//业务代码
}
2、修饰静态方法 (锁当前类)
给当前类加锁,会作用于类的所有对象实例 ,进入同步代码前要获得 当前 class 的锁。
这是因为静态成员不属于任何一个实例对象,归整个类所有,不依赖于类的特定实例,被类的所有实例共享。
synchronized static void method() {
//业务代码
}
静态 synchronized
方法和非静态 synchronized
方法之间的调用互斥么?不互斥!如果一个线程 A 调用一个实例对象的非静态 synchronized
方法,而线程 B 需要调用这个实例对象所属类的静态 synchronized
方法,是允许的,不会发生互斥现象,因为访问静态 synchronized
方法占用的锁是当前类的锁,而访问非静态 synchronized
方法占用的锁是当前实例对象锁。
3、修饰代码块 (锁指定对象/类)
对括号里指定的对象/类加锁:
synchronized(object) synchronized(this)
表示进入同步代码库前要获得 给定对象的锁。synchronized(类.class)
表示进入同步代码前要获得 给定 Class 的锁synchronized(this) {
//业务代码
}
4、类锁有两种实现方式:
synchronized
加在static
方法上(静态方法锁)。synchronized(*.class
)代码块。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。