synchronized的作用是实现线程间同步,它的工作是对同步代码块加锁,使得每一次只能有一个线程进入同步块,从而保证线程间安全性。
synchronized有三种用法:
- 指定加锁对象:对给定的对象加锁,进入同步代码块前要获得给定对象的锁。
- 直接作用于实例方法:相当于对当前实例加锁,进入同步代码块前要获得当前实例的锁。
- 直接作用于静态方法:相当于对当前类加锁,进入同步代码块前要获得当前类的锁
JVM基于进入和退出Monitor对象来实现方法同步和代码块同步。
monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁。
synchronized用的锁是存在Java对象头里的。
public class Synchronized {
public static void main(String[] args) {
// 对Synchronized Class对象进行加锁
synchronized (Synchronized.class) {
}
// 静态同步方法,对Synchronized Class对象进行加锁
m();
}
public static synchronized void m() {
}
}
在Synchronized.class同级目录执行javap–v Synchronized.class部分相关输出
public static void main(java.lang.String[]);
// 方法修饰符,表示:public staticflags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: ldc #1 // class com/murdock/books/multithread/book/Synchronized
2: dup
3: monitorenter // monitorenter:监视器进入,获取锁
4: monitorexit // monitorexit:监视器退出,释放锁
5: invokestatic #16 // Method m:()V
8: return
public static synchronized void m();
// 方法修饰符,表示: public static synchronized
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=0, locals=0
对于同步块的实现使用了monitorenter和monitorexit指令,而同步方法则是依靠方法修饰符上的ACC_SYNCHRONIZED来完成的。无论采用哪种方式,其本质是对一个对象的监视器(monitor)进行获取,而这个获取过程是排他的,也就是同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。
实时内容请关注微信公众号,公众号与博客同时更新:程序员星星

264

被折叠的 条评论
为什么被折叠?



