您的位置:首页 > 其它

深入synchronized原理详解

2017-05-12 12:34 387 查看
synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例,因为Class数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;当synchronized作用于某一个对象实例时,锁住的便是对应的代码块。在HotSpot JVM实现中,锁有个专门的名字:对象监视器(monitor)。

synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例 。

下面我们来说说synchronized在JVM中工作过程

public class SynchronizedThis {

public void methodA(){
synchronized (this) {
System.out.println("this A start:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("this A end:"+Thread.currentThread().getName());
}
}

public synchronized void methodB(){
System.out.println("this B start:"+Thread.currentThread().getName());
System.out.println("this B end:"+Thread.currentThread().getName());
}
}


首先看下synchronized反汇编结果

D:\xiaonuo\abc\src\com\thread>javac SynchronizedThis.java
D:\xiaonuo\abc\src\com\thread>javap -c SynchronizedThis.class
Compiled from "SynchronizedThis.java"
public class com.thread.SynchronizedThis {
public com.thread.SynchronizedThis();
Code:
0: aload_0
1: invokespecial #1                  // Method java/lang/Object."<init>":()V
4: return
public void methodA();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter //进入到一个同步线程,这个线程被锁住
4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
7: new           #3                  // class java/lang/StringBuilder
10: dup
11: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
14: ldc           #5                  // String this A start:
16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
22: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
25: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
34: ldc2_w        #11                 // long 1000l
37: invokestatic  #13                 // Method java/lang/Thread.sleep:(J)V
40: goto          48
43: astore_2
44: aload_2
45: invokevirtual #15                 // Method java/lang/InterruptedException.printStackTrace:()V
48: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
51: new           #3                  // class java/lang/StringBuilder
54: dup
55: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
58: ldc           #16                 // String this A end:
60: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
63: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
66: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
69: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
72: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
75: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
78: aload_1
79: monitorexit
80: goto          88
83: astore_3
84: aload_1
85: monitorexit // 离开线程,释放锁
86: aload_3
87: athrow
88: return
Exception table:
from    to  target type
34    40    43   Class java/lang/InterruptedException
4    80    83   any
83    86    83   any
public synchronized void methodB();
Code:
0: getstatic     #2   //  获取指定类的静态域,并将其值压入栈顶   // Field java/lang/System.out:Ljava/io/PrintStream;
3: new           #3                  // class java/lang/StringBuilder
6: dup
7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
10: ldc           #17                 // String this B start:
12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
18: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
33: new           #3                  // class java/lang/StringBuilder
36: dup
37: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
40: ldc           #18                 // String this B end:
42: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
45: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
48: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
51: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
54: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
57: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
60: return
}


上面全是JVM的一些命令,JVM的具体执行过程我也是一头雾水,欢迎一起探讨学习。

MethodA 是synchronized(this)通过反汇编可以看出是通过monitor来控制线程访问,但是MethodB没有体现出monitor来,有清楚的大牛们可以多多留言指点,谢谢

我通过网上查询资料synchronized方法反汇编之后在常量池中会有ACC_SYNCHRONIZED标示符, JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成(出自http://www.cnblogs.com/paddix/

在JVM中synchronized是通过监视器(monitor)来控制线程的访问,每个对象都会有一个monitor,如果monitor为0,线程可以进入monitor执行,然后monitor置为1,该monitor被该线程持有,如果该线程再次访问可以继续执行,并且monitor累计加1。此时如果其他线程要访问monitor,由于该monitor被上个线程占用,其他线程将被阻塞,知道上个线程运行完毕并且monitor置为0,该线程才能访问。

因此,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐