ReentrantLock 源码分析 - 并发基础类

前言

接下来会用 3-4 篇文章来分析 ReentrantLock的源码,本文先来打点基础。

阅读本文之前需了解以下内容:

  • 原子性的概念
  • CAS 的概念
  • ReentrantLock是独占锁且可重入
  • ReentrantLock既可以是非公平锁,也可以是公平锁

以上小知识也可以参考上一篇文章ReentrantLock 源码分析 - 并发小知识

正文

分析 ReentrantLock之前,需要简单了解以下三个基础类:

  • sun.misc.Unsafe
  • java.util.concurrent.locks.LockSupport
  • java.util.concurrent.locks.AbstractQueuedSynchronizer

这三个类,本文会粗略提一下他们的功能,有个大概印象即可, 第三个类是重点, 后面的文章还会详细讲到。

1. Unsafe 类

Unsafe类位于 JDK 的 rt.jar 包中, 它提供了硬件级别的 原子性 操作,Unsafe类中的方法都是 native 方法。

我们主要看下面三个方法:

// 比较 Object 中偏移量为 offset 的变量的值是否与 expect 相等,
// 如果相等则使用 update 更新并返回 true
// 如果不相当,返回 false
public final native boolean compareAndSwapInt(Object o, long offset, int expect, int update);

// 阻塞当前线程
public native void park(boolean var1, long var2);

// 唤醒调用 park 方法而阻塞的线程
public native void unpark(Object var1);

2. LockSupport 类

LockSupport类中也有相应的 parkunpark方法,内部实现也是基于 Unsafe类对应的方法, 当然作用也是一样的。

public static void park(Object blocker) {
	// 省略部分代码
	unsafe.park()
}

public static void unpark(Thread thread) {
	// 省略部分逻辑
	unsafe.unpark()
}

3. AbstractQueuedSynchronizer 类

AbstractQueuedSynchronizer是分析的重点, 来详细看下。

3.1 AbstractQueuedSynchronizer 的方法

AbstractQueuedSynchronizer类通过调用 LockSupportUnsafe对应的方法去实现以下三个功能。

// 获取独占资源
public final void acquire(int arg) {
	  // 最终会调用
	  LockSupport.park();
}
 
// 释放独占资源
public final boolean release(int arg) {
     // 最终会调用
   	LockSupport.unpark();
}
 
 // CAS 操作
protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
3.2 AbstractQueuedSynchronizer 简单介绍

AbstractQueuedSynchronizer是一个抽象类,中文可以翻译为 抽象同步队列, 简称 AQS,是一个双向队列,队列中的节点定义为 NodeNode里面存放有具体的线程,简易图如下:

AbstractQueuedSynchronizer是实现 ReentrantLockReentrantReadWriteLock, CountDownlatch等同步器的基础。

3.3 AbstractQueuedSynchronizer 的作用

我们就拿 ReentrantLock来说明 AbstractQueuedSynchronizer的作用。ReentrantLock内部持有 AbstractQueuedSynchronizer相应实现的引用。

// ReentrantLock 源码
public class ReentrantLock implements Lock, java.io.Serializable {
    
    private final Sync sync;
    
	abstract static class Sync extends AbstractQueuedSynchronizer {
        // 省略部分内容
    }
}

来看一个ReentrantLock的具体使用

ReentrantLock lock = new ReentrantLock();  

// 对共享资源进行操作
public void dealShareResource() throws InterruptedException {
  
    try {
		    lock.lock();
           // doSomething
    } finally {
        lock.unlock();
    }
  
}

从代码使用上看,并不能看出 AQS 到底起到了什么作用,下面用一张图来描述 AQS 在 lock 过程中的作用:

假设有三个线程同时去调用 dealShareResource方法,会去获取锁, 如果 thread1先抢到锁,那么其余的线程(thread2,thread3)就会放到 AQS 队列当中,其他细节这里先不提。

3.4 AbstractQueuedSynchronizer 的属性

我们知道 ReentrantLock是一个可重入锁,而它的这个特性就是基于 AbstractQueuedSynchronizerstate属性

属性定义

private volatile int state;
  • 作用一

    • 一个线程过来,如果 state为 0 表示锁没有被占用
    • 调用 compareAndSetState(0, 1)方法
    • 期望获得的是 0,如果是 0,就把 state更新为 1
  • 作用二

    • 一个线程 A 过来, 如果 state > 0,表示锁被线程 B 占用了,
    • 然后判断 线程A 是否就是 线程 B
    • 如果是 state++, 否则放入 AQS 队列

总结

本文是对阅读 ReentrantLock源码之前做的准备工作, 简单了解了三个类的基本作用:

  • sun.misc.Unsafe
  • java.util.concurrent.locks.LockSupport
  • java.util.concurrent.locks.AbstractQueuedSynchronizer

他们的调用关系是由下而上。 ReentrantLock
持有AbstractQueuedSynchronizer具体实现,通过调用ReentrantLocklockunlock方法,最终会去调用 AbstractQueuedSynchronizer相应的方法,最后实现同步功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值