5、ReentrantLock

ReentrantLock 是 java并发包下互斥锁,功能和synchronized差不多。但是他们的实现原理有很大差别,是基于操作系统互斥量实现的,依赖于JVM的实现,而ReentrantLock 是AQS的经典实现,是java 代码层面的实现的。随着jvm的升级,对锁的优化越来越好。我们在选择锁的时候,synchronized 和ReentrantLock 的性能不在是主要考虑的因素,可以结合自己的业务场景,合理的选择锁的实现。

1、ReentrantLock的用法

public class ReentrantLockTest {

    private static ReentrantLock lock = new ReentrantLock();
    private static int i = 0;

    public static void main(String[] args) {
        try{
            lock.lock();//获取锁
            i++;
        }finally {
            lock.unlock();//一定要在finally中释放锁,否则处理过程中出现异常,锁永远不会被释放
        }
    }
}

2、ReentrantLock 的原理

ReentrantLock 是基于AQS独占锁实现的,前文已经说过了AQS的原理。这里就说说ReentrantLock 的实现。
之前说过,AQS作为同步器的基础,维护了一个state(同步状态),这个state含义的由子类自己定义。

在 ReentrantLock 中state 被定义为锁的重入次数(所以又叫可重入锁)。当state=0,说明没有线程拥有锁,线程每次获取锁就把state + 1。相反每次释放锁state - 1,重入了多少次锁,就必须释放多少次锁。ReentrantLock 又分为公平锁 和非公平锁。下面分别看看代码如何实现。

先看看公平锁

       final void lock() {
            //调用AQS 中的acquire 方法。acquire 会调用tryAcquire 来判断是否获取锁成功
            acquire(1);
        }

        /**
         * tryAcquire 方法在AQS中说过,
         * 是留给子类现实独占模式获取锁。
         * 返回true 表示获取成功,false表示获取锁失败
         * 
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {//表示没有当前线程拥有锁
                //之前没有节点,设置state属性,并将拥有锁的线程设置为当前线程
                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;
        }

在看看非公平锁

      // 与公共锁相比。线程一开始就尝试获取锁,并不管是否有线程拥有锁或者在排队等待,
      // 导致的结果就是先排队的不一定比后面来的先 获取到锁
      final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        //尝试获取锁 直接点用了nonfairTryAcquire
        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;
        }

熟悉了AQS的原理之后,在来看ReentrantLock 感觉很简单,只需要实现尝试获取锁的方法就可以了,那么问题来了,我们可用实现这个方法做一个分布式锁吗?

你可能感兴趣的:(5、ReentrantLock)