• ReentrantLock源码简析


    概念

    ReentrantLock,可重入锁。在多线程中,可以通过加锁保证线程安全。

    加锁和解锁

    • 加锁:
    public void lock() {
        sync.lock();
    }
    
    • 解锁
    public void unlock() {
        sync.release(1);
    }
    

    内部类Sync继承AQS(AbstractQueuedSynchronizer),因此可以维护状态变量state,通过acquire()获取state、release()释放state。后文会涉及。

    构造方法

    • 无参构造方法

    默认使用非公平锁。

    /**
     * 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类

    Sync类是一个继承AQS的内部静态抽象类。

    Sync继承AQS,因此也可以维护状态变量state,通过acquire()获取state、release()释放state。

    公平锁FairSync和非公平锁NonfairSync,都继承Sync类,并且重写了Sync类中的抽象方法Lock()。

    其中的nonfairTryAcquire()方法,是ReentrantLock最核心的实现。

    如果状态变量state为0,说明目前还没有其他线程加锁,当前线程可以进行加锁,通过CAS将状态变量state加1。
    并且当前线程会获得锁。

    如果状态变量state不为0,且获取锁的是当前线程,则将state加1。

        /**
         * Base of synchronization control for this lock. Subclassed
         * into fair and nonfair versions below. Uses AQS state to
         * represent the number of holds on the lock.
         */
        abstract static class Sync extends AbstractQueuedSynchronizer {
            private static final long serialVersionUID = -5179523762034025860L;
    
            /**
             * Performs {@link Lock#lock}. The main reason for subclassing
             * is to allow fast path for nonfair version.
             */
            abstract void lock();
    
            /**
             * Performs non-fair tryLock.  tryAcquire is implemented in
             * subclasses, but both need nonfair try for trylock method.
             */
            final boolean nonfairTryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                //如果状态变量state为0,说明目前还没有其他线程加锁,当前线程可以进行加锁,通过CAS将状态变量state加1。
                //并且当前线程会获得锁。
                if (c == 0) {
                    if (compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                //如果状态变量state不为0,且获取锁的是当前线程,则将state加1。
                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
            protected final boolean tryRelease(int releases) {
                int c = getState() - releases;
                if (Thread.currentThread() != getExclusiveOwnerThread())
                    throw new IllegalMonitorStateException();
                boolean free = false;
                //如果state为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();
            }
    
            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 the instance from a stream (that is, deserializes it).
             */
            private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
                s.defaultReadObject();
                setState(0); // reset to unlocked state
            }
        }
    

    非公平锁和公平锁

    非公平锁和公平锁,都重写了tryAcquire()。而acquire()是AQS中的方法。

    • 非公平锁:

    非公平锁的调用过程: lock()---> acquire(1) ---> tryAcquire(1) ---> nonfairTryAcquire(1)

    /**
     * Sync object for non-fair locks
     */
    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() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
    
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
    
    • 公平锁:

    主要流程:lock()--->acquire(1)--->tryAcquire(1)---> hasQueuedPredecessors()

    公平锁和非公平锁的主要区别是:

    公平锁,会去判断“当前线程”是不是AQS的线程等待队列(CLH队列)中的第一个线程,并对state进行CAS操作。

    这个区别在hasQueuedPredecessors()方法中体现。

        /**
         * Sync object for fair locks
         */
        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();
                //如果当前状态变量为0(也就是没有线程获取到锁)
                if (c == 0) {
                    //判断“当前线程”是不是AQS的线程等待队列(CLH队列)中的第一个线程,并对state进行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;
            }
        }
    

    ReentrantLock和Synchronized的区别

    • Synchronized是基于监视锁monitor实现的,当monitor为0时,线程能够获得锁,此时monitor加1。当有线程进行请求时,判断monitor是否为0,如果不为0,说明锁已经被其他线程拿到了。Synchronized是JVM级别的锁。

    而ReentrantLock是基于AQS实现的,AQS是一个抽象队列容器。当有线程发起请求时,如果是公平锁,需要在队列中排除等待。如果是非公平锁,会插队。

    • Synchronized可以是方法锁、对象锁。

    而ReentrantLock可以在代码中灵活地加锁、解锁。但要注意,必须在finally中进行unlock()。

    其他资料

    AQS详情见: https://www.cnblogs.com/expiator/p/12052125.html

  • 相关阅读:
    python 远程 部署和运行
    学习笔记——UML类图
    Core Data 多线程操作实战篇
    Core Data系列六——Custom Migration
    Core Data系列五——数据迁移方案
    NSOperation以及NSOperationQueue的使用
    Magical Record设计小谈
    Core Data系列四——多线程设计
    Core Data系列三——基本使用
    Core Data系列二——基础概念
  • 原文地址:https://www.cnblogs.com/expiator/p/12066632.html
Copyright © 2020-2023  润新知