您当前的位置: 首页 > 

恐龙弟旺仔

暂无认证

  • 1浏览

    0关注

    282博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

JDK源码解析之ReentrantLock

恐龙弟旺仔 发布时间:2019-01-15 18:06:12 ,浏览量:1

前言:

    之前说过,JDK有两种锁的方式,一种是Synchronized,一种就是CAS

    基于CAS实现的Unsafe我们无法直接使用,我们一般就是使用ReentrantLock来实现锁的功能

    那么本文我们就来看下ReentrantLock是如何实现CAS锁的

 

    建议读者也看一下关于AbstractQueuedSynchronizer的源码解析,AQS作为一个基础类,ReentrantLock会用到里面的很多方法

    可以参考下笔者的另一篇博客:JDK源码解析之AbstractQueuedSynchronizer

 

1.ReentrantLock结构分析
public class ReentrantLock implements Lock, java.io.Serializable {
    // 只有这么一个成员变量
    private final Sync sync;
    
    // 两种构造方法
    public ReentrantLock() {
        // 默认是非公平锁
        sync = new NonfairSync();
    }
    public ReentrantLock(boolean fair) {
        // 可以让用户自主选择公平锁或非公平锁
        sync = fair ? new FairSync() : new NonfairSync();
    }
    1)有关于ReentrantLock.Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -5179523762034025860L;

    abstract void lock();

    ...
}
    2)ReentrantLock.FairSync公平锁
static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        ...
    }
}
    3)ReentrantLock.NonFairSync非公平锁
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

    总结:通过上面的结构分析可知

    基础的实现类就是Sync,而Sync继承了AQS

    非公平锁NonFairSync继承了Sync

    公平锁FairSync也继承了Sync

 

    4)ReentrantLock的基本使用

    就是我们之前看过的ArrayBlockingQueue.offer(E e)

// ArrayBlockingQueue.offer(E e)
public boolean offer(E e) {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    // 获取锁
    lock.lock();
    try {
        if (count == items.length)
            return false;
        else {
            enqueue(e);
            return true;
        }
    } finally {
        // 释放锁
        lock.unlock();
    }
}

    由上例可知:ReentrantLock的使用还是比较简单的,lock()方法就是用来获取锁;unlock()就是用来释放锁。

    下面来着重分析一下这两个方法(我们来分析默认的非公平锁)

 

2.ReentrantLock.lock()获取锁(非公平锁NonFairSync)
// ReentrantLock.lock()
public void lock() {
    sync.lock();
}

// NonFairSync.lock()
final void lock() {
    // 使用cas设置state为1
    if (compareAndSetState(0, 1))
        // 如果设置成功则置当前线程为独占线程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // 如果设置state失败,说明已经被其他线程设置成功了,
        // 则进入AQS.acquire方法
        // 关于acquire的具体细节可以参考笔者关于AQS分析的博客
        acquire(1);
}

// AbstractQueuedSynchronizer.compareAndSetState()
protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

    总结:NonFairSync.lock()方法还是比较简单的,直接就是使用CAS来设置AQS.state=1,成功则说明当前线程已经竞争到锁,可以继续下面的业务处理;如果失败,则说明当前线程竞争锁失败,需要进入队列等待锁被释放继续后面的竞争。

 

3.ReentrantLock.unlock()释放锁(非公平锁NonFairSync)
// ReentrantLock.unlock()
public void unlock() {
    sync.release(1);
}

// NonFairSync.release()
// 直接就进入了AQS.release()
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

    总结:ReentrantLock.unlock()直接就调用了AQS.release()

    具体不再分析,读者可参考JDK源码解析之AbstractQueuedSynchronizer​​​​​​​

 

4.ReentrantLock的其他加锁方式  

    1)ReentrantLock.tryLock()尝试锁,如果失败则直接返回,不再等待

// ReentrantLock.tryLock()
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}

// Sync.nonfairTryAcquire()
final boolean nonfairTryAcquire(int acquires) {
    // 1.获取当前线程及状态
    final Thread current = Thread.currentThread();
    int c = getState();
    // state=0则意味着没有线程获取到锁,使用CAS将state设置为1,
    // 返回true代表当前线程获取到锁
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    
    // 2.如果发现c!=0但是持有锁的线程是当前线程的话,
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        // state累加,如果            
关注
打赏
1655041699
查看更多评论
0.0406s