ReentrantLock.lock();

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReentrantLock.lock();相关的知识,希望对你有一定的参考价值。

reentrantlock对象,里面有一个state属性,volatile的,对其进行cas操作,可以作为锁使用。

ReentrantLock lock = new ReentrantLock();

lock.lock();方法调用的是sync.lock()方法,sync是ReentrantLock的全局变量名,如果调用无参构造函数,生成的是一个非公平的lock,调用带参数可以确定是公平锁还是非公平。

非公平锁,的lock方法,调用的是,

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

逻辑是,把state变量,也就是那个锁,置换成1的状态,加锁,如果成功了,就把lock对象当前的锁定线程赋值为当前线程。

如果没成功,说明现在是加锁的,那么执行acqire()方法

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

逻辑是,先执行tryAcquire方法

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


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

 

就是先试着再去加锁一次,如果还没成功,再检测加锁的是否是当前线程,如果是的话,那么重入,把state值加一

如果以上都不成功,那么返回false

接下来看acquireQueued方法

 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;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }




这个是AbstractQueuedSynchronizer抽象类的方法,给Sync继承,

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

先看addwaiter方法,在Sync对象的尾部(lock对象其实只是对sync对象的封装,sync才是真正的锁,sync对象内部除了一个volatile的锁state,还有两个node节点(node节点内部有一个前驱指针,一个后续指针,一个存线程引用的变量),一个指向头(头内部没有有用数据),一个指向尾部tail,保留一个等待这个锁的线程队列,

在这里实现公平非公平,addwaiter方法,就是把当前没有获取到锁的线程,做成一个node封装起来,放在队列最后,并返回这个node。

 

acquireQueued方法,有空再看

 

以上是关于ReentrantLock.lock();的主要内容,如果未能解决你的问题,请参考以下文章

AQS

第十一周学习视频

深入显出一篇能懂Java锁机制,Synchronized和ReentrantLock

深入显出一篇能懂Java锁机制,Synchronized和ReentrantLock

二探ReentrantLock非公平锁的加解锁过程

二探ReentrantLock非公平锁的加解锁过程