深入synchronized原理详解
2017-05-12 12:34
387 查看
synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例,因为Class数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;当synchronized作用于某一个对象实例时,锁住的便是对应的代码块。在HotSpot JVM实现中,锁有个专门的名字:对象监视器(monitor)。
synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例 。
下面我们来说说synchronized在JVM中工作过程
首先看下synchronized反汇编结果
上面全是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的异常的原因。
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的异常的原因。
相关文章推荐
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- 深入理解Oracle表(5):三大表连接方式详解之Hash Join的定义,原理,算法,成本,模式和位图
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- 深入Java集合学习之HashMap的实现原理详解
- dhcp 协议重点原理深入详解
- 深入理解PHP之OpCode原理详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- 《深入理解mybatis原理(一)》 Mybatis初始化机制详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- 深入了解View实现原理以及自定义View详解
- 深入了解View实现原理以及自定义View详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- Android中View绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- 转:synchronized和LOCK的实现原理---深入JVM锁机制
- Java多线程-synchronized深入解析及原理
- 《深入理解mybatis原理(三)》 MyBatis的一级缓存实现详解 及使用注意事项