java多线程-ReentranLock源码解析

一、ReentranLock的三个内部静态类FairSync、NonFairSync、Sync之间的关系

FairSync和NonFairSync都是继承Sync这个抽象类;

    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();

        /**
        *1、获取当前线程
        *2、获取当前线程的state
        *3、如果state为零,那么表示当前线程在此之前并没有获得锁,因此需要竞争锁去第4步,
            如果当前的线程的state大于零,那么表示这个线程拥有锁,只是再一次申请锁转向第6步
        *4、通过CAS的方式来判断当前线程是否获得锁,如果compareAndSetState(0, acquires)返回true,
            那么线程获得锁转向第5步,否则转向第7步
        *5、通过setExclusiveOwnerThread()方法将当前线程设置成独占锁的那个线程,返回true
        *6、如果当前线程是独占锁的那个线程,那么我们将state = state+aquires,返回true
        *7、以上步骤如果执行完了,没有返回,那么表示锁竞争失败,所以返回false
        */
        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;
        }
        //
        /**
        *释放锁和之前的重入锁的过程是差不多的
        *1、获取当前线程
        *2、判断当前线程是否是独占锁的那个线程
        *3、如果是,那么我们将state设置成0
        *4、同时我们将setExclusiveOwnerThread设置成null,表示当前没有线程独占该锁
        *5、回写state
        *6、释放成功返回true
        *7、返回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;
        }
        //如果占有锁的线程就是当前线程那么返回true
        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();
        }


        //返回独占锁的那个线程,如果state=0,则没有线程占有锁,如果state>0,则返回独占锁的线程
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        /**
        *如果占有锁的线程是当前线程返回true,
        *那么我们就返回state就行,state表示ReentranLock重入的次数
        */
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        //如果当前线程的state为零,那么表示线程并没有获得锁,返回false,否则返回true
        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
        }
    }

NofairSync类

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /***
         *通过CAS的方式去竞争锁,如果竞争成功则将当前线程设置成独占锁的那个线程,
         *反之,调用acquire(1),这个方法后面具体解析
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        //尝试去获得锁,使用的是父类Sync的nonFairTryAcquire()
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

FairSync类

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

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

        /**
         * 公平锁实现了一个尝试获取锁的方法,
         * 1、获取当前线程,以及当前线程的state
         * 2、如果当前线程的state为零,那么表明当前线程之前并没有获得锁,那么转向步骤3,
         *    如果state不为零,则转向当前锁采用重入的方式,只要对state+1这个变量进行修改就可以了
         * 3、首先判断hasQueuedPredecessors(),如果返回false,
         *    则表明该线程之前还有线程的前面没有等待队列,执行第4步。
         *    如果返回true,那么表示这个线程之前还有线程在等待,尝试获取锁失败,那么则结束返回false
         * 4、如果前面没有线程在等待,那么当前线程就采用CAS的方式获取锁,
         *    获取成功则将当前线程设置为独占当前锁的线程,如果设置失败,那么将返回false
         * 
         * 
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                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;
        }
    }
总结:
  • 对于lock(),FairSync相较于NonFairSync少了使用尝试使用CAS设置state获取锁的步骤
  • 对于tryquire(),FairSync在尝试获取锁的时候需要判断等待队列是否有线程在等待,而NonSync直接使用CAS设置state的方式将线程设置成独占锁的线程。

ReentranLock的构造方法和使用建议

ReentranLock分为公平锁和非公平锁;我们可以看一下公平锁和非公平锁是如何定义的
1、公平锁定义方式

Lock fairLock = new ReentranLock(true); 

2、非公平锁定义方式

Lock unfairLock = new ReentranLock();
//或者
Lock unfairLock = new ReentranLock(false);

3、我们看一下ReentranLock构造方法是如何定义一个公平锁的

private final Sync sync;
//非公平锁构造器
public ReentrantLock() {
        sync = new NonfairSync();
    }
/**
 * 公/非公平平锁构造器
 * fair = true 时返回一个new FairSync()
 * fair = false 时返回一个NonFairSync()
 */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

4、ReentranLock类的lock方法

/**
 * sync根据前面构造器定义的方式返回的对象会自动的去调用子类
 * 如果sync引用的是FairSync,那么就调用FairLock的lock()方法
 * 如果引用的是NonFairSync,那么就调用FairLock的lock()方法
 * 
 */
public void lock() {
        sync.lock();
    }

5、FairSync和NonFairSync获取锁的方式的差异性

//FairSync 直接调用调用acquire()方法获取锁
final void lock() {
    acquire(1);
}


/***
 *通过CAS的方式去竞争锁,如果竞争成功则将当前线程设置成独占锁的那个线程,
 *反之,调用acquire(1),这个方法后面具体解析
 */
final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

这里我们看到lock方法调用了acquire方法,但是我们发现FairSync和NonFairSync以及Sync这个类中都没有acquire()方法。因此我们想到去Sync的超类AbstractQueuedSynchronizer找到这个方法

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

//AbstractQueuedSynchronizer的tryAcquire(int arg)方法
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

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

参考文章

https://www.cnblogs.com/java-zhao/p/5131544.html

猜你喜欢

转载自blog.csdn.net/makeliwei1/article/details/80959463