Java并发编程学习笔记:synchronized

本文详细介绍了Java中`synchronized`关键字在实例方法、静态方法和代码块中的应用,探讨了其底层原理,包括锁的四种状态(无锁、偏向锁、轻量级锁、重量级锁)以及锁升级的过程,以优化并发性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、synchronized关键字

实例方法

作用在类的普通方法上,锁的是当前对象实例。构造方法本身是线程安全的,不能使用synchronized关键字修饰。

synchronized void function() {}

静态方法

作用在类的静态方法上,锁的是当前类class。

synchronized static void function() {}

代码块

作用在代码块上,锁的是指定的对象实例或者class。

synchronized (object) {}
synchronized (class) {}

二、底层原理

synchronized 关键字底层原理属于 JVM,个人感觉就是信号量和PV操作理论的实际应用。

synchronized 同步语句块的实现使用的是 monitorenter(指令指向同步代码块的开始位置)monitorexit (指令则指明同步代码块的结束位置)

  • 在执行monitorenter时,会尝试获取对象的锁,如果锁的计数器为 0 则表示锁可以被获取,获取后将锁计数器设为 1 也就是加 1。

  • 对象锁的的拥有者线程才可以执行 monitorexit 指令来释放锁。在执行 monitorexit 指令后,将锁计数器设为 0,表明锁被释放,其他线程可以尝试获取锁。

  • 如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止。

synchronized 修饰的方法用到的是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法,从而去执行相对应的同步方法。

使用synchronized修饰方法和代码块的本质都是对对象监视器 monitor 的获取,每个 Java 对象都可以关联一个 Monitor 对象,不加 synchronized 的对象不会关联监视器。

监视器的主要功能就是提供互斥访问、线程同步、等待与唤醒等机制,是实现信号量机制PV的核心。

三、锁的升级

锁的状态

无锁: 对于共享资源,不涉及多线程的竞争访问。

偏向锁: 在只有一个线程连续多次获取同一个锁对象时,JVM会将锁偏向于该线程。后续该线程进入同步块时,只需检查是否为偏向锁持有者即可,无需进行其他加锁动作。当其他线程尝试获取该锁时,偏向锁才会撤销并升级为轻量级锁或重量级锁。

轻量级锁: 当多个线程同时申请共享资源锁的访问时,这就产生了竞争,JVM尝试使用CAS操作来快速获得锁 (通过自旋的方式循环尝试获取锁,不阻塞线程采用循环等待)。如果自旋一定次数后仍无法获取到锁,则轻量级锁会膨胀成重量级锁,以防止无谓的CPU空转。

重量级锁: 如果共享资源锁已经被某个线程持有,此时是偏向锁状态,未释放锁前,再有其他线程来竞争时,则会升级到重量级锁。在轻量级锁状态多线程竞争锁时,也会升级到重量级锁。重量级锁由操作系统来实现,是传统的互斥锁的实现方式(确保一次只有一个线程可以访问临界区资源),所以性能消耗相对较高。

这4种级别的锁,在获取时性能消耗逐渐增加,也是锁升级的方向。

锁升级

锁升级是针对于synchronized锁在不同竞争条件下的一种优化,根据锁在多线程中竞争的程度和状态,可在无锁、偏向锁、轻量级锁和重量级锁之间进行流转,以降低获取锁的成本,提高获取锁的性能。锁升级的过程是不可逆的。

无锁到偏向锁: 当一个线程访问同步代码块并获取锁时,如果此时没有其他线程竞争该锁,那么JVM会把锁对象的标识符设置为这个获得锁的线程ID,并将锁对象的状态标记为偏向模式。持有偏向锁的线程在进入和退出同步代码块时,只需要检查当前线程ID是否与锁对象的标识符一致即可,无需执行CAS等复杂的操作。

JDK1.5版本后默认关闭了偏向锁。如果未开启偏向锁,线程访问共享资源则直接由无锁升级为轻量级锁。

偏向锁升级至轻量级锁: 当有第二个线程尝试获取已被偏向的锁时,偏向锁会撤销并升级为轻量级锁。在轻量级锁状态下,线程首先会在栈上创建一个“锁记录”结构(Lock Record),然后尝试通过CAS操作将其替换为对象头中的锁标志位。 如果CAS成功,表示线程获得了锁;如果失败,则表示存在其他线程的竞争,此时会自旋一段时间再次尝试获取锁。当自旋超过一定次数仍无法获取时,轻量级锁就会膨胀成重量级锁。

轻量级锁升级至重量级锁: 升级后,线程会被操作系统挂起,放入等待队列,由操作系统的线程调度器来决定何时唤醒线程继续争夺锁资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值