ReentrantLock源码分析(JDK 1.7)

eentrantLock是一个可重入的互斥锁(独占锁),它和隐式锁(使用Synchronized修饰的方法)一样有着相同的功能和语义。但是ReentrantLock还扩展了一些特别功能。

ReentrantLock属于最后一个成功lock的线程,且在该线程未释放(unlock)之前。
成功获取lock分为下面两种情况
1.在当前没有任何其他线程拥有锁(lock过且未unlock)情况下,一个线程调用lock立马返回结果(不阻塞)
2.从名字我们也可以知道Reentrant是可重入的意思,如果当前线程已经lock过,那么它再次lock时候也是立马返回结果(不阻塞)。可以使用方法 isHeldByCurrentThread, and getHoldCount得知当前线程是否已经lock过和lock重入的次数

ReentrantLock提供两种重入锁机制
1.公平锁。
描述:公平锁即lock时候,如果AQS同步等待队列里有同样在等待lock的线程,那么该次lock会进入AQS同步等待队列的尾节点,阻塞排队依次等待lock.
2.非公平锁。
描述:非公平锁即lock时候,调用CAS指令抢占式的更新状态值(可能同时多个线程共同竞争CAS更新状态值,也可能和AQS同步队列的头节点共同竞争更新值),如果成功更新状态值,则成功获取lock,否则阻塞排队等待lock.

两种锁的对比:公平锁的总吞吐量要低于非公平锁。

既然ReentrantLock提供了两种机制的重入锁,那么对于用户来说肯定也得有相对应的获取方法。
ReentrantLock有两个构造函数:
1.无参构造(默认是非公平锁,性能好)
2.带有fairness 布尔值的形参的构造函数。
fairness = true :公平锁
fairness = false :非公平锁

注意:在ReentrantLock里,有个比较特殊的方法tryLock(),它总是使用非公平锁的lock方法。即无论我们选择哪种机制锁,在调用tryLock时候,总是使用非公平锁的lock方法。

在使用ReentrantLock时候,需要注意使用方式。可以参考下面的使用方式:
class X {
private final ReentrantLock lock = new ReentrantLock();
// …

public void m() {
lock.lock(); // block until condition holds
try {
// … method body
} finally {
//一定要记住unlock!!!
lock.unlock()
}
}
}

如果对ReentrantLock序列化,那么当反序列化时候,得到的总是unLock状态(即使已经lock,序列化再反序列化,还能成功lock)

由于ReentrantLock使用的AbstractQueueSynchronized,该AQS使用的是int类型的state。所以ReentrantLock最多支持int值范围2147483647次的重入次数.
想要更多的重入次数可以使用AbstractQueuedLongSynchronizer来仿造个ReentrantLock。AbstractQueuedLongSynchronizer使用的是long型的state,支持long范围内的state。

下面看看ReentrantLock的源码部分。ReentrantLock内部实现了个Sync继承于AQS,整个ReentrantLock几乎都只是代理了Sync方法。如果你熟悉AQS的话,随便翻下ReentrantLock源码即可,没必要看那些英文。
如果读者未了解的AQS的话,建议先了解AQS。


public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;

    /**
    该ReentrantLock 实现同步机制的基础类。Sync 有两个版本子类(公平和非公平)。
    ReentrantLock 主要使用AQS的state值来控制独占锁的。
    **/
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        //主要原因是因为非公平锁需要CAS快速尝试(相对应公平锁)
        abstract void lock();


        /**
        这个方法相当于AQS的ryAcquire,为什么非公平版的TryAcquire代码需要写在父类Sync 这里?
        前面也说到过需要注意tryLock,它是只调用非公平版的tryLock。而ReentrantLock 是代理了
        Sync ,根据多态机制。所以非公平版的TryAcquire只能写在父类Sync这里了。
        **/
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //如果c==0,代表当前没任何线程持有锁(lock过)
            if (c == 0) {
                //CAS更新状态值
                if (compareAndSetState(0, acquires)) {
                    //更新成功,代表成功获取锁,设置当前线程到OwnerThread
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
           //如果当前线程已经拥有锁,则重入次数+acquires(隐式锁Synchronized也具有重入语义)
            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;
        }
       //释放状态releases
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            //必须得拥有锁才能释放锁!
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            //注意这里得c==0才代表释放成功
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
       //相当于Object的wait 、signal、signalAll功能,但是更加灵活强大,比如一个独占锁可以拥有多个条件谓词
        final ConditionObject newCondition() {
            return new ConditionObject();
        }
        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
       //获取当前重入次数
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
       //判断是否已有线程成功获取锁
        final boolean isLocked() {
            return getState() != 0;
        }
        /**
         * Reconstitutes this lock instance from a stream.
         * @param s the stream
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

   //非公平版的Lock
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            //尝试CAS抢占修改state值(无视AQS等待队列),如果成功则立马返回,否则阻塞等待了。。
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
    //公平版的Lock
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        final void lock() {
            acquire(1);
        }
        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //这里多了个hasQueuedPredecessors,即判断当前AQS同步等待队列中是否有正在等待的节点
                //如果存在,则添加返回false,添加到AQS同步等待队列依次等待lock.所有这里会造成吞吐量的损耗
                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;
        }
    }
    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    /**
    这里仅仅只是代理了sync.lock();。
    如果没有其他线程拥有锁,那么该调用该方法会立即返回(成功获取锁),且设置当前线程的锁次数为1。
    如果当前线程已经成功获取过锁,那么调用该方法会设置 锁次数+1,然后立即返回。
    如果锁已经被其他线程所获取,那么当前线程会被加入到AQS的同步等待队列,且挂起当前线程,直到
    它被唤醒再次成功获取锁,然后设置锁次数为1返回
    **/
    public void lock() {
        sync.lock();
    }
    /**
     * Acquires the lock unless the current thread is
     * {@linkplain Thread#interrupt interrupted}.
     *
     * <p>Acquires the lock if it is not held by another thread and returns
     * immediately, setting the lock hold count to one.
     *
     * <p>If the current thread already holds this lock then the hold count
     * is incremented by one and the method returns immediately.
     *
     * <p>If the lock is held by another thread then the
     * current thread becomes disabled for thread scheduling
     * purposes and lies dormant until one of two things happens:
     *
     * <ul>
     *
     * <li>The lock is acquired by the current thread; or
     *
     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
     * current thread.
     *
     * </ul>
     *
     * <p>If the lock is acquired by the current thread then the lock hold
     * count is set to one.
     *
     * <p>If the current thread:
     *
     * <ul>
     *
     * <li>has its interrupted status set on entry to this method; or
     *
     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
     * the lock,
     *
     * </ul>
     *
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared.
     *
     * <p>In this implementation, as this method is an explicit
     * interruption point, preference is given to responding to the
     * interrupt over normal or reentrant acquisition of the lock.
     *
     * @throws InterruptedException if the current thread is interrupted
     */
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    /**
       在调用tryLock方法时候,如果锁未被其他线程所占有,且该方法返回的值返回true,那么则代表成功获取锁。
       无论当前的ReentrantLock使用的是公平排队机制还是有其他线程在AQS的等待队列等待获取锁,在调用该
       方法时候也会立马返回CAS竞争获取锁的结果。 即使该方法打破了公平机制,但是他在某些情况下是有用的。
       如果想使用公平机制的tryLock的话,那么可以通过使用tryLock(0, TimeUnit.SECONDS)来达到公平机制。
      看下面tryLock(0, TimeUnit.SECONDS)代码就明白了
    **/
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
   /**
        该方法和tryLock()差不多,都是得到一个布尔值来判断是否成功获取锁。
        tryLock(long timeout, TimeUnit unit)相对无参的tryLock不同之处
        1.  tryLock(long timeout, TimeUnit unit)可以支持指定的一个时间段内等待成功获取锁。如果遇到下面三种情况,则立即返回
                1)已经成功获取锁
                2)该线程已被其他线程中断
                3)设置的等待时间已经到达。
        2. tryLock(long timeout, TimeUnit unit)可以根据当前ReentrantLock使用的公平或者非公平机制来获取锁

    **/
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    /**
    尝试释放当前锁。
    如果当前线程拥有锁,则该锁的次数-1。如果锁的state-1后,值为0.那么则代表当前线程完全释放锁成功。
    如果当前线程不拥有锁,那么则会抛出IllegalMonitorStateException异常。
    **/
    public void unlock() {
        sync.release(1);
    }
    /**
    获取一个属于当前Lock实例的Condition实例。
    该Condition有着和在使用内置锁时候的Object的监视器方法(wait,notify,notifyAll)一样的功能。
    如果当前线程没有拥有锁,那么在调用Condition的await,signal这些方法时候回抛出IllegalMonitorStateException异常
    Condition队列中的节点是根据FIFO的结构来signall节点的

    当调用Condition的await方法时候,当前锁会被释放(清除state)且保存被释放的state值,然后挂起当前线程,直到当前
    线程被signal,此时在该方法结束返回前会恢复先前保存的state值。

    如果在await期间,发现线程已被中断,那么则会终止当前的await。抛出InterruptedException异常且清除线程的interrupted 状态值

    **/
    public Condition newCondition() {
        return sync.newCondition();
    }
    /**
    获取当前线程获取锁的次数
    **/
    public int getHoldCount() {
        return sync.getHoldCount();
    }
   /**
    判断当前线程是否拥有锁
    **/
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }
    /**
     * Queries if this lock is held by any thread. This method is
     * designed for use in monitoring of the system state,
     * not for synchronization control.
     *
     * @return {@code true} if any thread holds this lock and
     *         {@code false} otherwise
     */
    public boolean isLocked() {
        return sync.isLocked();
    }
    //判断是否是公平锁。  true==公平锁
    public final boolean isFair() {
        return sync instanceof FairSync;
    }

    /**
    获取当前拥有锁的线程。如果没有任何线程拥有,则返回null。
    当调用这个方法时候,由于在并发情况下,AQS只能尽可能获取正确的结果。
    因为有可能其他线程刚刚修改完state成功,还未来得及设置其他线程到own里面去。
    所以这时我们获取的话那么就可能为null。
    **/
    protected Thread getOwner() {
        return sync.getOwner();
    }

    /**
    查询是否有节点(线程)在AQS队列中等待获取锁。由于队列中等待的节点可能随时因为一些
    情况而被取消,所以即使返回true,也不代表队列中的节点(线程)最终能获取到锁。
    **/
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }
     /**
    查询给定的线程thread是否在AQS等待队列中,如果在则返回true,否则false
    **/
    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }

    /**
    获取当前在AQS同步队列中等待获取锁的节点(线程)个数的近似值。由于是通过迭代
    AQS同步队列来计算节点个数的,在迭代过程中,节点结构有可能修改,因此得到的只能
    是近似值。
    **/
    public final int getQueueLength() {
        return sync.getQueueLength();
    }
   /**    
    获取在AQS同步队列中等待获取锁的线程的集合。由于是通过迭代AQS同步队列来收集线程的,
    在迭代过程中,节点结构有可能修改,因此得到的只能是近似值。
    **/
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }
    /**
   查询当前独占锁下的条件队列中是否有节点(即当前独占锁下的Condition是否有线程在await) 
    **/
    public boolean hasWaiters(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    /**
   获取当前独占锁下的条件队列中节点(即当前独占锁下的Condition是否有线程在await)的个数.
    也是近似值 
    **/
    public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
    }
   /**
     获取当前独占锁下的条件队列中节点(即当前独占锁下的Condition是否有线程在await)的线程集合
    **/
    protected Collection<Thread> getWaitingThreads(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
    }
    /**
     * Returns a string identifying this lock, as well as its lock state.
     * The state, in brackets, includes either the String {@code "Unlocked"}
     * or the String {@code "Locked by"} followed by the
     * {@linkplain Thread#getName name} of the owning thread.
     *
     * @return a string identifying this lock, as well as its lock state
     */
    public String toString() {
        Thread o = sync.getOwner();
        return super.toString() + ((o == null) ?
                                   "[Unlocked]" :
                                   "[Locked by thread " + o.getName() + "]");
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值