ReentrantLock

学习自

https://blog.csdn.net/yanyan19880509/article/details/52345422

 

一家人可以不用排队——重入

非公平实现:如果井没人用,正在交接,可以插队一波;如果井有人用,只能乖乖排队

 

对应一下

 

默认的非公平锁——lock与unlock

lock

final void lock() {
    if (compareAndSetState(0, 1))//如果没人用,我用用试试看,非公平!
        setExclusiveOwnerThread(Thread.currentThread());
    else//结果不行
        acquire(1);
}
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {//又非公平!
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    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;
}
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//队尾添加节点,然后阻塞线程,但是在阻塞前还会争取一下
        selfInterrupt();
}

unlock

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;
}

公平就不看了, 大同小异

 

condition

await

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();//新建一个节点并加到等待队列中去
    int savedState = fullyRelease(node);//释放当前锁
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {//如果当前节点已经时候Node.CONDITION了
        LockSupport.park(this);//阻塞当前线程
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

signal

public final void signal() {
    if (!isHeldExclusively())//如果不是当前线程独占中
        throw new IllegalMonitorStateException();
    Node first = firstWaiter;
    if (first != null)
        doSignal(first);//唤醒第一个
}
private void doSignal(Node first) {
    do {
        if ( (firstWaiter = first.nextWaiter) == null)//null统一
            lastWaiter = null;
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&//如果唤醒失败,且成员变量firstWaiter不为空,那就再次进行循环
             (first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
    /*
     * If cannot change waitStatus, the node has been cancelled.
     */
    if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))//设置状态
        return false;

    /*
     * Splice onto queue and try to set waitStatus of predecessor to
     * indicate that thread is (probably) waiting. If cancelled or
     * attempt to set waitStatus fails, wake up to resync (in which
     * case the waitStatus can be transiently and harmlessly wrong).
     */
    Node p = enq(node);
    int ws = p.waitStatus;
    if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);//唤醒
    return true;
}

写到一半,发现这样不行,还是讲模型吧!

 

lock unlock

AQS的state,0代表无人使用,1代表1个人在使用,1以上代表单个线程重入了。

在lock的时候,因为默认是非公平的,所以会尝试性地cas 0-1,也就是如果没人用,会尝试性地插队。

插队失败,就会生成一个CONDITION的Node,添加到队列中,并休眠自己。

unlock的时候,state减去1,如果发现到0了,那么就会唤醒链表头部的Node。

(如果是公平的话,那么lock的时候,就不会插队了)

 

await signal

在await的时候,会把所有线程都加入等待队列中去,并且休眠这些线程。同时state-1。在signal的时候,会把这些节点,1个或者所有都加入到释放队列中,这个时候还不会唤醒,因为唤醒线程还在使用资源,state>=1。知道唤醒线程unlock或者await的时候,才会开始唤醒这个释放队列,他们又开始重新竞争。(此外,只有当前获取资源的线程才能await与signal)

 

condition更可以是多条件

new Thread(new Runnable() {
    @Override
    public void run() {

        //加锁
        reentrantLock.lock();

        try {

            Log.i(TAG, "我睡着了");

            //沉睡
            condition1.await();
            condition2.await();

            Log.i(TAG, "我睡醒了");

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {

            //解锁
            reentrantLock.unlock();
        }

    }
}).start();

其实和单条件是差不多的。只要你当前在使用资源,而且调用了condition.await,那你就得睡。对你生效的只有一个锁,因为你已经睡着了,执行不到另一个condition.await,所以一次性最多对一个condition睡觉。当你被唤醒了,再执行下面的await,然后又睡了。

此外,这些不同的condition,俨然是不同的队列。

 

lock interruptibly

为何他能响应中断呢?假如该线程被interrupt了,那么中断标志位也响应改变了。在lock interruptibly的时候,会第一时间检查中断标记位,如果有,直接抛出中断异常。当然也有可能在开始排队后,被中断。这个时候回阻塞在park方法上,一旦被唤醒,会再次检测中断,如果已被标记位中断,也是直接抛出异常。

 

read write lock

这个我了解的不多,只知道分为读锁和写锁,其中读是可以存在并发的。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值