本旨在作学习记录,内容源自JavaGuide,作者在此基础上进行补充说明、整理论述,使其能以一种更为逻辑地清晰地方式表达出“请你说一下自己对synchronized关键字的理解”的理解,更多适应于java面试回答,亦可作对请你说一下自己对synchronized关键字的理解的简要了解。
一、synchronized关键字的作用
synchronized
关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行,它解决的是多个线程之间访问资源的同步性。
二、使用方式
①.修饰实例方法: 作用于当前对象实例加锁,进入同步代码前要获得 当前对象实例的锁。注意,不可用synchronized修饰构造方法。
synchronized void method() {
//业务代码
}
②.修饰静态方法: 也就是给当前类加锁,会作用于类的所有对象实例 ,进入同步代码前要获得 当前 class 的锁。因为静态成员不属于任何一个实例对象,是类成员( _static 表明这是该类的一个静态资源,不管 new 了多少个对象,只有一份)。所以,如果一个线程 A 调用一个实例对象的非静态 synchronized
方法,而线程 B 需要调用这个实例对象所属类的静态 synchronized
方法,是允许的,不会发生互斥现象,因为访问静态 synchronized
方法占用的锁是当前类的锁,而访问非静态 synchronized
方法占用的锁是当前实例对象锁。
synchronized static void method() {
//业务代码
}
③.修饰代码块 :指定加锁对象,对给定对象/类加锁。synchronized(this|object)
表示进入同步代码库前要获得给定对象的锁。synchronized(类.class)
表示进入同步代码前要获得 当前 class 的锁。
synchronized(this) {
//业务代码
}
综上:
对类上锁,防止多个线程中多个实例同时访问这个 类中的synchronized static 方法。它可以对类的所有对象实例起作用。
对对象实例上锁,防止多个线程中这一个实例同时访问这个类的synchronized 方法。
三、synchronized底层原理(通过字节码文件研究)
synchronized 关键字底层原理属于 JVM 层面。我们可以通过javac命令,将演示的java源码文件(.java文件)编译为字节码文件(.class文件)。接着,通过javap命令查看jvm层面的指令运行。
synchronized同步语句块的实现使用的是 monitorenter
和 monitorexit
指令,其中 monitorenter
指令指向同步代码块的开始位置,monitorexit
指令则指明同步代码块的结束位置。
synchronized修饰的方法并没有 monitorenter
指令和 monitorexit
指令,取得代之的确实是 ACC_SYNCHRONIZED
标识,该标识指明了该方法是一个同步方法。