【并发】Lock类的底层实现原理

6 篇文章 0 订阅

虽然都是用来实现锁功能,但是lock需要显式的获取和释放锁,而synchronized是隐式的获取和释放锁,虽然synchronized用起来比较方便,但lock能够以非块结构来实现互斥同步,更加自由。


同步器

队列同步器是lock如何完成线程同步的关键,同步器依赖内部的一个同步队列(FIFO的双端队列)来完成同步操作。

具体来说,就是如果当前线程获取同步状态失败(也就是获取锁失败),同步器就会把当前线程和等待状态等信息构造成一个节点(Node),并把这个节点加入同步队列,并阻塞这个线程。同步器里面有两个指针,一个head,一个tail,分别指向队列头和队列尾,队列的头结点表示获得同步状态成功的节点。同步器的构造如下:

 这个过程中重点是设置头结点和尾节点的操作细节:

1、设置尾节点(对应lock操作)

当一个线程获得同步状态之后,其他的线程因为无法获得同步状态,因为会被包装成一个节点加入队列尾,但是因为这个过程是并发的,因此加入队列尾的过程需要保证线程安全。因此,同步器提供了一个基于循环CAS来设置队列尾的方法。原理就是CAS。成功后,就会将原来的tail和这个节点利用指针完成关联,并把tail改成该节点:

 

2、设置头结点(对应unlock操作)

而设置首节点这个操作则是原本获得同步状态(也就是获得锁)的线程来完成的,由于只有一个线程能获得同步状态,因此这个过程是单线程的,不存在线程安全问题,也就不需要CAS操作。他只需要将首节点设置成他的后继结点,然后把后它的next和后继的pre指针改一下即可。


等待通知模式的实现

之前sychronized里面利用Object类的方法wait和notify来实现了等待通知模式,Condition接口也提供了类似的方法,用来和Lock类配合实现等待通知。

       Condition对象是由Lock对象创建出来的,使用Lock类的newCondition方法创建。调用condition的await方法,会释放锁并进行等待,然后等待其他线程调用condition的signal方法通知本线程,等待其他线程释放锁之后在获得锁继续执行。

condition具体实现等待队列

每个condition对象都包含一个等待队列,await()和signal()方法的实现其实本质上是等待队列里面的Node的入队列和出队列的操作(从同步队列入,出到同步队列)。

对于一个Synchronized来说,一个对象有一个同步队列,和一个等待队列,而Lock则有一个同步队列和多个等待队列。因为它可以有多个condition对象。结构如下:

每个condition都是同步器的内部类,或者说他都有所属的同步器的引用。

1、await()操作

执行await方法时,意味着当前线程一定有condition相关联的锁,因此首先会把同步队列的首节点取出,并构造成一个新节点,加入到condition的等待队列的末尾,同时释放锁,唤醒同步队列里面的后继结点,让他成为首节点,并让当前线程进入等待状态。

 2、signal()操作

首先判断当前线程是否获得了锁,如果获得了,那么取出等待队列里里面的首节点,然后把这个节点构造成新节点放入同步队列尾。来竞争锁,如果成功获得了锁,那么就会从之前的await方法返回。而所谓的signalAll()表示将等待队列里面的所有节点全部移到同步队列里面去。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值