ReentrantLock源码解析以及公平锁和非公平锁用例

要讲ReentrantLock,首先离不开Lock,因为它实现了Lock接口,先讲下Lock接口

Lock是Java的一个锁策略,相对于synchronized:

 1.Lock更加灵活,随着线程数量的增加,效率不会降低,反之synchronized关键字则会效率成反比下降;

 2.Lock提供多种加锁方案,这里从源码可以看出来,下面会讲到

 3.对于单线程来说,synchronized关键字效率高于Lock,可以根据场景自己选择需要哪种策略

接下来讲下Lock的源码:

———lock.lock()
           获取锁
———lock.lockInterruptibly()
           获取锁,除非当前线程被中断
———lock.tryLock()
           获取锁,但有一个条件就是锁这个时候处于空闲状态
———lock.tryLock(long time ,time unit)
           获取锁,但有一个条件就是锁这个时候处于空闲状态,在这个基础上加上一个等待时间
———lock.unLock()
           释放锁
———lock.newCondition()
           获取一个Condition实例,这个实例可以跟Lock实例绑定使用;而Condition的作用,就是与Lock对象结合使用,替代对象监视器

接下来讲下ReentrantLock类的源码:

首先来看下构造方法

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

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

根据解释,这个类为同步控制基础类;我们可以从接下来的公平锁和非公平锁可以看出来,这个类的作用

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

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

相信大家看到这里,已经看到了公平锁和非公平锁,有两个地方不一样,我先贴下

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

这里可以跟FairSync中的

tryAcquire(int acquires)方法比较一下

发现只有这里的不同

即hasQueuedPredecessors(),一个判断了这个状态,另一个没有

贴下这个方法的代码

  public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

这个方法的意思就是说,线程等待的时间不比当前线程的时间更长

如果返回false,即等待的时间比当前线程等待的时间更长,即为公平锁中获取锁的判断条件,否则为非公平锁。

其次还有一个地方,就是锁的lock方法;

//非公平锁   
final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
//公平锁
   final void lock() {
            acquire(1);
        }

这里我再贴下非公平锁中,if判断里面的方法

  /**
     * Atomically sets synchronization state to the given updated
     * value if the current state value equals the expected value.
     * This operation has memory semantics of a {@code volatile} read
     * and write.
     * 如果当前状态值等于预期值,自动将同步状态设置为给定的更新状态值
       此操作的内存语义为volatile读写。
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that the actual
     *         value was not equal to the expected value.
     */
    protected final boolean compareAndSetState(int expect, int update) {
        return U.compareAndSwapInt(this, STATE, expect, update);
    }

   /**
     * Sets the thread that currently owns exclusive access.
     * 设置当前拥有独占访问权的线程。
     * A {@code null} argument indicates that no thread owns access.
     * This method does not otherwise impose any synchronization or
     * {@code volatile} field accesses.
     * @param thread the owner thread
     */
    protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }

这里的意思也就是说,在非公平锁中,调用lock方法时,多加了一个状态值判断,根据这个判断,来设置下一个有锁的访问权的线程。这里我可能还没有讲明白,大家可以查看下

sun.misc.Unsafe U= sun.misc.Unsafe.getUnsafe();
U.compareAndSwapInt(this, STATE, expect, update);

这个方法的具体实现,相信会有一个理解。

到这里,对公平锁和非公平锁的定义和条件就讲解完毕了。

接下来看看ReentrantLock的其他方法,我这里只讲ReentrantLock独有的方法,由Lock实现来的方法不做讲解,用法和解释一样:

    
	//查询当前线程持有多少个锁
	public int getHoldCount() {
        return sync.getHoldCount();
    }
    //查询当前线程是否持有这个锁
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }
    //查询锁是否被某一个线程所持有
    public boolean isLocked() {
        return sync.isLocked();
    }
    //判断是否为公平锁
    public final boolean isFair() {
        return sync instanceof FairSync;
    }
    //返回当前拥有锁的线程,或者为空
    protected Thread getOwner() {
        return sync.getOwner();
    }
    //查询是否有线程在等待获取这个锁
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }
    //查询某个线程是否在等待获取这个锁
    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }
    //返回等待此锁的线程总数
    public final int getQueueLength() {
        return sync.getQueueLength();
    }
    //返回可能等待获取此锁的集合
    protected Collection getQueuedThreads() {
        return sync.getQueuedThreads();
    }
    //查询是否有线程在等待某个指定条件下关联的锁
    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);
    }
    //返回在等待某个指定条件下关联的锁的线程总数
    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);
    }

    //返回可能在等待某个指定条件下关联的锁的线程的集合
    protected Collection 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);
    }
    //返回锁的描述以及状态
    public String toString() {
        Thread o = sync.getOwner();
        return super.toString() + ((o == null) ?
                                   "[Unlocked]" :
                                   "[Locked by thread " + o.getName() + "]");
    }

源码看到这里,基本就讲解完毕了,可能大家的疑问点,还是在公平锁和非公平锁,具体是如何实现的,这个就得往下面继续深究了。我会继续研究,后续再出一篇关于这两个实现的文章,目前我还没有完全理解源码。

最后,给大家提供一个公平锁和非公平锁的简单用法例子:

package com.dhc.jstestdemo.lock;

import android.util.Log;

import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by 大漠dreamer on 2019/3/20.
 */
public class LockTest {
    public static final String TAG = LockTest.class.getSimpleName();
    //创建锁
    private ReentrantLock mLock;
    public LockTest() {
    }
    private LockTest(ReentrantLock mLock) {
        this.mLock = mLock;
    }
    /**
     * 设置锁
     */
    private void setLock(ReentrantLock lock) {
        try {
            lock.lock();
            if (lock.isFair()) {
                Log.d(TAG, "setFairLock: " + Thread.currentThread().getName() + "get Fair Lock");

            } else {
                Log.d(TAG, "setFairLock:" + Thread.currentThread().getName() + " get Unfair Lock");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    /**
     * 测试锁
     *
     * @param lock
     */
    private void testLock(final ReentrantLock lock) {
        final LockTest fairLock = new LockTest(lock);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "run: " + Thread.currentThread().getName() + "running");
                fairLock.setLock(lock);
            }
        };
        Thread[] threads = new Thread[5];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(runnable);
            threads[i].start();
        }
    }
    public void test() {
        testLock(new ReentrantLock(true));
        testLock(new ReentrantLock(false));
    }
}

给出最终执行的结果:

ReentrantLock源码解析以及公平锁和非公平锁用例_第1张图片

文章到这就结束了,谢谢阅读,有什么问题还请大家指出来,共同进步~

你可能感兴趣的:(Android)