ReentrantLock整理

ReentrantLock内部有一个继承于AQS的Sync类,正如AQS源码里所说的:AQS的子类们应该被定义为非公开的内部辅助类,并且被用来实现它们外部类的其它内部类的同步属性,即ReentrantLock一样,一个Sync内部类实现了AQS的一些同步方法,并且内部公平和非公平锁类调用了这一些方法来进行锁操作。
AQS还为ReentrantLock提供了一个原子值state来表示状态,ReentrantLock定义了改变这个状态值的get和set方法,并且定义这个状态值的意义,用来获取或释放对象。

我们一般都是这样使用ReentrantLock:
1、private final Lock lock = new ReentrantLock()
2、private final Lock lock = new ReentrantLock(Boolean fair)
3、lock.lock()
4、lock.unlock()

构造方法:

首先,第一种方法调用了ReentrantLock的无参构造器,默认创建了一个NonfairSync对象,代码如下:

public ReentrantLock() {
    sync = new NonfairSync();
}

第二种会按照传的参数来构造公平或非公平锁的对象

    public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

调用lock方法:

首先看内部类NonfairSync:

final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }

1、首先会直接判断State值,若为0,则将其置为1,并且将当前线程置为独享模式的持有者,并取得资源
2、否则会调用AQS中的acquire方法,然后acquire方法会调用NonfairSync中重写的tryAcquire方法来进行尝试获锁的判断

   final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        /*首先调用AQS的getState方法来获取state状态,值默认初始为0*/
        int c = getState();
        /*为0,证明没有线程持有锁,利用原子操作将state+1,并将当前线程设为当前独享模式的持有者,然后返回true*/
        if (c == 0) {
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }

3、若锁已被当前线程所占有,即状态值不为0,则将当前状态值设置为:当前状态值加上acquires参数(默认为1)。然后返回true,证明再次获锁成功。这块代码为可重入的体现

        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
         /*设置状态值为修改后的值*/
            setState(nextc);
           /*成功获锁*/
            return true;
        }

内部类FairSync:

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

这里是直接调用AQS中的acquire方法,然后acquire方法会调用FairSync中重写的tryAcquire方法来进行尝试获锁的判断

 protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        /*获取state值*/
        int c = getState();
        /*公平的体现。若state为0*/
        if (c == 0) {

当前节点为等待队列头节点并且能将state设置为acquires代表的值,则成功。这块代码与非公平锁不同的地方就在这,判断当前节点是否为头节点的操作,也是公平的体现,即每次只有队列中的第一个节点才能获取资源

            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }

若锁已被当前线程所占有,即状态值不为0,则将当前状态值设置为:当前状态值加上acquires参数(默认为1)。然后返回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;
    }
}

判断当前节点是否是队列中的第一个节点,是就返回false,不是则返回true

public final boolean hasQueuedPredecessors() {
/* 1、若当前队列为空,则h==t,返回false
   2、若当前队列只有一个节点,则返回false
   3、否则若当前线程所属节点不为第二个节点,返回true;若等于,返回false*/
    Node t = tail;
    Node h = head;
    Node s;
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

unlock的调用:

public void unlock() {
    sync.release(1);
}

它会调用AQS的release方法,然后release方法调用Sync重写的tryRelease方法来释放资源

protected final boolean tryRelease(int releases) {
        /*将当前状态值减去releases(默认1)*/
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
         /*标志位,若c=0,则返回true,不为0.返回false*/
        boolean free = false;
        /*若修改后的状态值为0,则证明可以释放,并将持有当前独享模式的线程置空*/
        if (c == 0) {
        /*设置标志位为0*/
            free = true;
            setExclusiveOwnerThread(null);
        }
        /*设置修改后的状态值*/
        setState(c);
        /*若free返回true*/
        return free;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值