首页IT科技java并发编程从入门到精通(Java并发编程 | Synchronized原理与使用)

java并发编程从入门到精通(Java并发编程 | Synchronized原理与使用)

时间2025-09-18 02:20:23分类IT科技浏览5506
导读:Java提供了多种机制实现多线程之间有需要同步执行的场景需求。其中最基本的是Synchronized ,实现上使用对象监视器( Monitor 。...

Java提供了多种机制实现多线程之间有需要同步执行的场景需求                 。其中最基本的是Synchronized                  ,实现上使用对象监视器( Monitor )                          。

Java中的每个对象都是与线程可以锁定或解锁的对象监视器( Monitor )关联         。在同一时间只有一个线程可以在对象监视器( Monitor )上保持锁定                 。任何其他线程试图锁定对象监视器( Monitor )都会被阻止                          ,直到它们可以获得该监视器上的锁定                          。

Synchronized 基本使用方式

Synchronized 的作用范围         ,依据锁定的对象(object                 、this                          、class)         、使用方式        ,可以分成五种情况         。如果按照JVM字节码的区别                          ,也可以分成两种形式:代码块(monitorenter        、monitorexit)                          、函数(ACC_SYNCHRONIZED)        。

虽然可以按照不同维度来划分 Synchronized 但本身机制是一样的                  ,无论是 Synchronized 函数/代码块        ,都是通过对象监视器( Monitor )来实现                          。无论是this                  、class        、object本质上都是一个对象                         ,区别无非代表的是当前实例                         、类                  、一般实例                  ,它们都有着对象监视器( Monitor )                 。

在HotSpot虚拟机中,对象监视器( Monitor ) 具体的实现类就是 ObjectMonitor(C++)        。

在使用/分析 Synchronized 同步是否有效正确的时候                         ,只需要分析需要的同步块是否作用在同一个对象监视器( Monitor )上                          。换一种描述                          ,是否作用在同一个对象(Object)上,这里(Object)可以是this、object                         、class                 。

下面分别按照Synchronized 代码块                          、Synchronized 函数维度来进行详细介绍。

Synchronized 代码块

Synchronized 代码块的一般使用形式:synchronized ( Expression ) Block                           。

Expression 必须是一个对象                 ,可以是class、this                 、object                          ,不能是原始类型(int                          、float...);否则编译的时候就会报错                          。如果 Expression 是null         ,会抛出NullPointerException 的异常。

Block表示一段逻辑代码                 ,执行逻辑代码前会锁定Expression 的对象监视器( Monitor )                 。如果正常运行完成后                          ,对象监视器( Monitor )会被释放;如果运行期间异常/中断了同样的也会释放对象监视器( Monitor )                          。先加锁确保其他线程无法进入执行         ,所以Synchronized 是悲观锁        ,JVM指令上使用monitorenter         、monitorexit 来进行相关实现         。

在字节码指令里可以也可以看到有两个monitorexit                           ,一个是正常运行后的释放;另一个是在异常(athrow)抛出前的释放                 。同一个线程可以多次进入被锁定的相同对象监视器( Monitor )                  ,所以Synchronized 是可重入锁                          。

Synchronized 函数

Synchronized函数在同步原理上同 Synchronized代码块是没有区别的        ,都是通过锁定对象监视器( Monitor );区别在于这里的对象是隐藏了起来         。同样的支持可重入        。

如果是静态方法(static)                         ,锁定的对象是这个方法所在的class object 对象                          。

如果是普通的方法                  ,锁定的是this(当前实例)对象                 。

编译成JVM字节码的时候,函数描述上会标识ACC_SYNCHRONIZED                          ,并不会在函数代码块中显示的使用monitorenter                 、monitorexit指令        。

调用函数前锁定对象监视器( Monitor )                          ,完成运行后释放对象监视器( Monitor )                          。无论函数是否有显性的抛出/处理异常,如果有异常中断抛出前也会自动的释放锁定的对象监视器( Monitor )                 。

Synchronized 实现原理

Synchronized同步一直也在进行优化                 ,也是跟随着JDK新理念一起发展。比如偏向锁                          、轻量锁         、重量锁        、适应性自旋等等机制                          。不同的JDK版本                          ,不同的JVM可能都有所不同                          。

在HotSpot虚拟机中         ,抛开锁升级                          、自适应等机制;基本原理是线程通过 CAS抢占对象监视器( Monitor ) _Owner来实现锁                 ,没有抢占的会进入 _EntryList 来进行放置。当然                          , 线程执行/中断释放_Owner后         ,_EntryList并不是简单按照FIFO来进行选择执行不会保证公平性        ,所以Synchronized是非公平锁                 。

图中_WaitSet没有体现用途                          ,但其是很重要的一个结构                  , 用于当 _Owner 执行线程中断时        ,线程将会写入                          。值得注意获取到锁之后才能中断                         ,等待锁时不可中断         。当相关线程被唤醒后                  ,会采有不同的策略重新回到_EntryList 或者 参与CAS竞争 _Owner,这里存在线程上下文切换的可能                 。

详细可以查看相关源码:

http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src

在最后综述下Synchronized 特性:悲观锁                  、可重入锁        、非公平锁                          。

欢迎长期关注公众号/头条号(Java研究者)

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
上传照片素材怎么赚钱(网站什么办法可以赚钱-揭秘图库网站出海商业模式与运营推广(上)) 查看一个进程对内存的占用率的影响(pmap命令 – 显示进程的内存映像信息)