ReetrantLock简单分析

ReetrantLock关键方法分析

构造方法
//非公平锁
public ReentrantLock() {
    sync = new NonfairSync();
}

//可以通过传入的值确认非公平锁和公平锁
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
内部类

内部维护了一个AQS(AbstractQueuedSynchronizer)作为公平锁、非公平锁的抽象类。
AQS是一个通过CAS方法维护的一个阻塞队列。

Sync内部类
//分析一下内部类
abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -5179523762034025860L;

    //在公平锁和非公平锁中具体实现
    abstract void lock();

     //用于非公平锁获取锁
    final boolean nonfairTryAcquire(int acquires) {
        //获取当前线程
        final Thread current = Thread.currentThread();
        //获取当前state值
        int c = getState();
        //state值在没有线程获取锁的时候为0,获得锁以后通过CAS方法更新,更新成功以后,并把当前线程设置为独享线程,返回true表示已经获取到锁了
        if (c == 0) {
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        //如果state值不为0,即锁被占用了,这个时候去比较独享线程跟当前线程的关系,如果是同一个线程,那么多就可以重入使用了。(可重入锁就是这么来的)
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            //记录新的值->当前值+请求值
            setState(nextc);
            return true;
        }
        return false;
    }

    //尝试释放锁
    protected final boolean tryRelease(int releases) {
        //当前state值-尝试释放的值
        int c = getState() - releases;
        //如果不是同一个线程,无法释放锁
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        //如果值为0,说明锁没有重入,锁可以被释放,将独享线程设置为空
        if (c == 0) {
            free = true;
            //独享现成为空
            setExclusiveOwnerThread(null);
        }
        //修改释放以后的state值
        setState(c);
        return free;
    }
    
    //判断是否时同一个线程
    protected final boolean isHeldExclusively() {
        thread is owner
        return getExclusiveOwnerThread() == Thread.currentThread();
    }
    
    //新建一个ConditionObject对象。通过这对象的signal和await方法实现跟Object中notify,await方法一样的效果。
    final ConditionObject newCondition() {
        return new ConditionObject();
    }

    //查看当前线程是否独占
    final Thread getOwner() {
        return getState() == 0 ? null : getExclusiveOwnerThread();
    }

    //查询当前线程保持此锁的次数
    final int getHoldCount() {
        return isHeldExclusively() ? getState() : 0;
    }
    
    //是否当前线程是否被锁
    final boolean isLocked() {
        return getState() != 0;
    }

    //这个方法根据注释,说是要反序列化用的
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0);
    }
}
非公平锁-NonfairSync
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);
            //当前线程尝试去拿锁->tryAcquire,如果没有拿到,并且放入队列了,当前线程就中断了
            //if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){selfInterrupt();}
            
    }
    
    //尝试获取锁
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}
公平锁-FairSync
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();
        //获取state
        int c = getState();
        //没有锁被持有的情况下
        if (c == 0) {
            /当前队列为空或本身是同步队列中的头结点并且CAS操作确认的时候,就让当前线程获得锁。
            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;
    }
}
方法
lock()
//具体看公平锁,非公平锁过程。
//这里其实是通过AQS中维护的一个队列来保证获取锁的顺序的。
//公平锁只是多加了一次对当前节点在列表是否在头部的一个判断实现。
public void lock() {
    sync.lock();
}

//深入AQS代码中看AQS的lock
//下面代码中每一个线程获取锁的时候,去调尝试拿锁,请求拿锁失败把当前线程放入了队列中,addWaiter(Node.EXCLUSIVE)
而且这里忽略掉已经中断的线程
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
        selfInterrupt();}
}


【addWaiter(Node.EXCLUSIVE)代码分析开始】
//新建了一个双向链表作为队列
private Node addWaiter(Node mode) {
    //新建一个节点,线程是当前线程,类型为独享锁类型
    Node node = new Node(Thread.currentThread(), mode);
    //指针指向链表尾部,当不为空的时候,将当前节点的先驱指向前一节点,
    通过CAS(如果是尾部节点指针,这里就指向当前节点)成功后,接下来就把尾部节点的后继指向当前节点。
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    
    //这个方法只是确定了这个双向列表的头部。大概的逻辑是这样,如果队列尾部为空的话,说明是一个空的链表,当前节点就是头部节点了
    enq(node);
    //这里其实很简单,上面判断过了列表不为空的情形,这里主要是判断列表空的情形。
    {
        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;
                    }
                }
            }
        }
    }
    
    return node;
}

【addWaiter(Node.EXCLUSIVE)代码分析结束】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值