浅谈Java并发(三)

前两篇介绍了并发为什么会带来不一致,Java中如何实现线程和常用的同步关键字volatile。本文接着来介绍下Java中的另一个关键字synchronized和JUC中的ReentrantLock。

Synchronized

在Java虚拟机中,synchronized的实现依赖于对象头(回想对象文章中的MarkWord)和Monitor对象。每个对象都有一个对象头,用于存储对象的元信息和状态标志。当一个线程需要进入synchronized块时,它会首先尝试获取对象的Monitor对象。如果Monitor对象已经被锁定,则当前线程会进入等待队列中,等待锁释放;否则,当前线程就可以获取Monitor对象,并通过将自己的哈希码写入对象的对象头将它标记为已锁定。

在Java虚拟机的实现中,Monitor对象通常表示为一种内部数据结构(也称为管程)。它包含了一些用于控制并发访问的状态变量和等待队列,以及一些管理锁和解锁的方法。具体来说,当一个线程获得锁时,该线程的持有计数器会递增1。当其他线程需要进入synchronized块时,它们会尝试获取Monitor对象。如果Monitor对象已经被其他线程锁定,并且当前线程不在等待队列中,则该线程会将自己加入到等待队列中,然后被阻塞。当Monitor对象的持有者释放锁时,Monitor对象会通知等待队列中的线程,唤醒其中的一个或多个线程,让它们尝试重新获得锁。

需要注意的是,使用synchronized我们无法控制等待队列中的哪一个线程被唤醒(Java的线程调度是抢占式),因此可能导致线程饥饿。而且在实现层面,加锁、释放锁和唤醒线程等都需要操作系统从用户态进入内核态,因此对性能有比较大的影响。

ReentrantLock

在实现上,ReentrantLock依赖于AbstractQueuedSynchronizer(AQS)和Condition对象。AQS是一个用于构建同步器的基础框架,它提供了一些原子操作和队列管理方法,以支持各种同步机制的实现。Condition对象是一种用于线程间通信的机制,它可以让线程在等待某个条件成立时暂停执行,并在条件满足时恢复执行。

具体来说,当一个线程需要进入ReentrantLock块时,它会首先尝试获取锁。如果锁已经被其他线程占用,则当前线程会进入等待队列中;否则,当前线程就可以获取锁,并将它标记为已锁定。

在ReentrantLock的实现中,锁的状态是由AQS对象来维护的。每个ReentrantLock对象都有一个关联的AQS对象,用于记录当前锁的状态和管理等待队列。当一个线程获得锁时,该线程的持有计数器会递增1,并将自己加入到AQS的持有者列表中。当其他线程需要进入ReentrantLock块时,它们会尝试获取锁。如果锁已经被其他线程占用,并且当前线程不是锁的持有者,则该线程会将自己加入到AQS的等待队列中,并被阻塞。当ReentrantLock的持有者释放锁时,AQS会通知等待队列中的线程,唤醒其中的一个或多个线程,让它们尝试重新获得锁。

因为实现更加的复杂,所以ReentrantLock支持如下三个synchronized不支持的操作:

  1. 等待可中断:当前线程在一段时间内尝试获取锁,如果失败可以放弃等待,执行其他任务。在同步代码耗时很长的情况下很好用。
  2. 公平锁:替代抢占式实现FIFO,但是该操作会影响性能(有兴趣可以想一下原因)。
  3. 锁绑定多个条件:可以创建多个condition进行关联,适用于复杂场景。

选择

前文提到ReentrantLock功能是synchronized的超集,那么我们是不是可以直接将synchronized打入冷宫了,遇事不决ReentrantLock就好了?在《深入理解JVM虚拟机》一书中,周志明老师认为synchronized仍然有不可替代的地位,仍然推荐在功能满足的前提下优先使用synchronized,理由有以下三点:

  1. synchronized是Java语法层面的同步,简单且清晰。
  2. ReentrantLock必须在finally中保证lock被正确释放,而synchronized不需要在代码层面做妥协,由JVM保证锁会释放。
  3. 长远来看,JVM对synchronized的优化会更加容易。因为JVM可以在线程和对象元数据中记录锁的相关信息,而ReentrantLock中JVM获得这些信息比较困难。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值