ReentrantLock源码分析

ReentrantLock是Java并发包中提供的一个可重入的互斥锁ReentrantLocksynchronized在基本用法,行为语义上都是类似的,同样都具有可重入性。只不过相比原生的Synchronized,ReentrantLock增加了一些高级的扩展功能,比如它可以实现公平锁,同时也可以绑定多个Conditon

AbstractQueuedSynchronizer

ReentrantLock实现的前提就是AbstractQueuedSynchronizer,简称AQS,是java.util.concurrent的核心,CountDownLatch、FutureTask、Semaphore、ReentrantLock等都有一个内部类是这个抽象类的子类。先用两张表格介绍一下AQS。第一个讲的是Node,由于AQS是基于FIFO队列的实现,因此必然存在一个个节点,Node就是一个节点,Node里面有:

Node SHARED = new Node() 表示Node处于共享模式
Node EXCLUSIVE = null 表示Node处于独占模式
int CANCELLED = 1 因为超时或者中断,Node被设置为取消状态,被取消的Node不应该去竞争锁,只能保持取消状态不变,
不能转换为其他状态,处于这种状态的Node会被踢出队列,被GC回收
int SIGNAL = -1 表示这个Node的继任Node被阻塞了,到时需要通知它
 int CONDITION = -2 表示这个Node在条件队列中,因为等待某个条件而被阻塞 
int PROPAGATE = -3 使用在共享模式头Node有可能处于这种状态, 表示锁的下一次获取可以无条件传播
 int waitStatus 0,新Node会处于这种状态 
 Node prev 队列中某个Node的前驱Node 
 Node next 队列中某个Node的后继Node 
Thread thread 这个Node持有的线程,表示等待锁的线程
Node nextWaiter 表示下一个等待condition的Node

看一下AQS的方法和变量

Thread exclusiveOwnerThread 这个是AQS父类AbstractOwnableSynchronizer的属性,表示独占模式同步器的当前拥有者
Node 上面已经介绍过了,FIFO队列的基本单位
Node head FIFO队列中的头Node
Node tail FIFO队列中的尾Node
int state 同步状态,0表示未锁
int getState() 获取同步状态
setState(int newState) 设置同步状态
boolean compareAndSetState(int expect, int update) 利用CAS进行State的设置 
 long spinForTimeoutThreshold = 1000L 线程自旋等待的时间 
Node enq(final Node node) 插入一个Node到FIFO队列中 
Node addWaiter(Node mode) 为当前线程和指定模式创建并扩充一个等待队列
void setHead(Node node) 设置队列的头Node
void unparkSuccessor(Node node) 如果存在的话,唤起Node持有的线程
void doReleaseShared() 共享模式下做释放锁的动作
void cancelAcquire(Node node) 取消正在进行的Node获取锁的尝试
boolean shouldParkAfterFailedAcquire(Node pred, Node node)在尝试获取锁失败后是否应该禁用当前线程并等待
void selfInterrupt() 中断当前线程本身
boolean parkAndCheckInterrupt() 禁用当前线程进入等待状态并中断线程本身
boolean acquireQueued(final Node node, int arg) 队列中的线程获取锁
tryAcquire(int arg) 尝试获得锁(由AQS的子类实现它)
tryRelease(int arg) 尝试释放锁(由AQS的子类实现它)
isHeldExclusively() 是否独自持有锁
acquire(int arg) 获取锁
release(int arg) 释放锁
compareAndSetHead(Node update) 利用CAS设置头Node
compareAndSetTail(Node expect, Node update) 利用CAS设置尾Node
compareAndSetWaitStatus(Node node, int expect, int update)利用CAS设置某个Node中的等待状态

ReentrantLock的实现

Sync extends AbstractQueuedSynchronizer
FairSync能够保证先到的线程先拿到锁, 而NonfairSync不能保证
公平锁 FairSync extends  Sync
非公平锁    NonfairSync extends  Sync


看一下NonfairSync  lock源码实现

NonfairSync lock 源码解析
final void lock() {
//使用CAS占用锁成功并且设置为独占线程 
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
    }
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
//尝试获取锁
protected final boolean tryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
//获取持有锁的线程数  
int c = getState();
if (c == 0) {
//利用CAS获取锁 并设置为独占线程
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//判断获取锁锁的线程是否为当前线程 如果是 state+1 
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
//获取锁失败 将当前线程写入队列
private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        Node pred = tail;
//队列中有节点 使用CAS写入队尾
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }

        enq(node);
        return node;
    }
//自旋加上CAS保证一定写入队列
private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }
//将当前线程挂起
final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
//获取上一节点
                final Node p = node.predecessor();
//如果是头接点 尝试获取锁
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
//如果当前线程需要挂起  使用LockSupport.park挂起 
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
//如果状态为-1则表示当前线程可以被安全挂起  
        if (ws == Node.SIGNAL)
                 return true;
//如果大于0表示前一个节点处于被取消的状态,直接剔除该状态的节点  
        if (ws > 0) {
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
//修改pred的状态为SINGAL -1,且不挂起当前线程  
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }


释放锁的源码解析

unlock释放锁

public void unlock() {
        sync.release(1);
    }
public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
//唤醒被挂起的线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
//尝试释放锁
protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
}

FairSync公平锁的源码和NonfairSync非公平锁差别不大 不作讲解


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值