一 、ReenTrantLock(重入锁)
- 继承关系
ReenTrantLock实现Lock和序列化接口
Lock接口提供的方法有:
void lock();//加锁操作
void lockInterruptibly() throws InterruptedException;//可中断加锁
boolean tryLock();//尝试性的进行加锁
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;//在有限时间内进行尝试性加锁
void unlock();//释放锁
Condition newCondition(); //通信类
三个内部类:Sync、NonfairSync、FairSync
1) 抽象类Sync继承了 AbstractQueuedSynchronizer(AQS)类
2) NonfairSync继承 Sync抽象类
3) FairSync继承 Sync抽象类
- 构造函数
ReentrantLock() { //无参构造,创建一个 ReentrantLock 的实例。默认非公平性锁
sync = new NonfairSync();
}
ReentrantLock(boolean fair){ //创建一个具有给定公平策略的 ReentrantLock,默认false采用非公平性锁
sync = fair ? new FairSync() : new NonfairSync();
}
- 基本属性
private final Sync sync; //抽象sync类型的sync
- 常用方法
方法 | 作用 |
---|---|
int getHoldCount() | 查询当前线程获取此锁的次数。 |
isHeldByCurrentThread() | 查询当前线程是否获取此锁 |
final Thread getOwner() | 返回目前获取此锁的线程, |
boolean hasQueuedThreads() | 查询是否有线程正在等待获取锁 |
boolean hasQueuedThread() | 判断传进来的线程是否处于阻塞队列中 |
boolean hasWaiters(Condition condition) | 判断当前condition的实例是否处于wait状态 |
void lockInterruptibly() | 如果当前线程未被中断,则获取锁 |
boolean tryLock() | 仅在调用时锁未被另一个线程保持的情况下,才获取该锁 |
void unlock() | 试图释放锁 |
Condition newCondition() | 返回用来与此 Lock 实例一起使用的 Condition 实例。 |
-
重入锁的实现
ReentrantLock锁的实现中使用到AQS(AbstractQueuedSynchronizer)类:
线程获取锁会修改state值,当前线程每获取一次锁会对state做+1操作,未获取锁则放入AQS提供的队列中,线程释放锁会对state-1,当state=0时才真正释放锁 -
三大主要的内部类
==①Sync:继承AbstractQueuedSynchronizer ==
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock();
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
//获取当前锁的状态:0空闲,>0占用,<0溢出
int c = getState();
if (c == 0) {//空闲
//CAS获取锁,获取成功则将state置为1,并且将当前线程记录下来,直接返回
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);//记录当前线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //锁不是空闲,且是当前线程获取的锁
int nextc = c + acquires;
if (nextc < 0) //溢出
throw new Error("Maximum lock count exceeded"); //获取锁次数到达上限直接抛出异常
setState(nextc); //若没到达上限,则直接更新state,直接返回
return true;
}
return false; //若当前获取锁的线程不是当前的线程,返回false
}
//释放锁操作
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
//如果当前获取锁的线程不是当前的线程,抛出异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//当state减为1的时候才真正释放锁,将持有锁的线程置为null
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);//把当前获取锁的线程置为null
}
setState(c);
return free;
}
//序列化需要重写的方法!
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0);
}
}
②NonfairSync(非公平性锁):继承 Sync抽象类
两次抢锁:
1.第一次通过CAS强制抢锁,
2.强制抢锁失败则第二次尝试性抢锁,
a.首先判断当前锁是否空闲(state=0),是则直接通过CAS获取锁,获取成功则修改state且将当前线程写入AQS中。
b.在锁占用的情况下,占用锁的线程为当前线程则直接修改state,成功返回。
c.以上都不满足,失败返回
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
//先通过CAS强制获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else //获取失败,尝试抢锁
acquire(1); //调用AQS的acquire方法
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
//AQS的 acquire()方法
public final void acquire(int arg) {
//如果tryAcquire为false直接放入队列中
if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
③fairSync(公平性锁):继承Sync抽象类
一次抢锁:
1.尝试性获取锁,
如果锁空闲,判断当前线程是否满足条件(判断AQS队列为空或者当前线程是否处于队列的队头),
修改state,将当前线程记录到AQS中,成功返回)
如果锁被占用,并且是当前线程占有锁,修改state,成功返回
如果都不满足,则失败返回
2.如果未获取到锁,则将线程加入AQS中的队列
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//!hasQueuedPredecessors():当前队列为空并且当前线程为队列中处于头结点的线程
if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
//AQS的 hasQueuedPredecessors()方法
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
//返回 队列不为空 && (队列中只有一个节点 || 当前线程不等于头结点存储的线程)
return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
}
-
AbstractQueuedSynchronizer类
这个类基于FIFO队列,没有获取到锁的线程放入队列中,可以用于构建锁或者其他相关同步装置的基础框架。该同步器(以下简称同步器)利用了一个int类型的state来表示状态:
state=0表示锁是空闲状态
state>0表示锁被占用
state<0表示溢出FIFO队列中的元素Node就是保存着线程引用和线程状态的容器,
每个线程对同步器的访问,都可以看做是队列中的一个节点Node。Node的主要包含以下成员变量:
Node {
int waitStatus;//节点的状态
Node prev;//前驱节点
Node next;//后继节点
Node nextWaiter;//存储condition队列中的后继节点
Thread thread;//入队列时的当前线程
}
//节点的状态:
static final class Node {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
//CANCELLED,值为1,表示当前的线程被取消;
static final int SIGNAL = -1;
//SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark;
static final int CONDITION = -2;
//CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中
static final int PROPAGATE = -3;
//PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行;值为0,表示当前节点在sync队列中,等待着获取锁。