锁之ReentrantLock

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了锁之ReentrantLock相关的知识,希望对你有一定的参考价值。

源码结构图

技术分享图片

Lock源码

public interface Lock {

  //获取锁
  void lock();

 /**
  *当前线程的锁没有中断才能获取锁
  * if (Thread.interrupted())
  *        throw new InterruptedException();
  */
  void lockInterruptibly() throws InterruptedException;

    //获取锁是否成功。true表示获取到锁,false表示没有获取到锁
  boolean tryLock();

     // 尝试获取锁,并等待指定的时间
   boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

   // 释放锁
   void unlock();

   // LOCK条件
   Condition newCondition();
}

ReentrantLock源码

public class ReentrantLock implements Lock, java.io.Serializable {
  // 同步器,是整个锁机制的实现者
  private final Sync sync;

  // 定义的抽象静态内部类。实现基本的功能
    abstract static class Sync extends AbstractQueuedSynchronizer {
         // 抽象方法。由公平锁和非公平锁自己实现
        abstract void lock();

            // 释放锁
            protected final boolean tryRelease(int releases) {
                  // 锁的计数器。释放一次计数器减1,直到为0,则整个锁完全释放,才能被其他线程获取该锁。
            int c = getState() - releases;
                        // 此类型锁是可重入锁。因此是以thread为粒度的。必须判断当前线程是否与持有锁线程一致。
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
                        // 当锁的计数器为0时,整个锁释放。
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

                // 默认实现的一个非公平锁的获取尝试获取方法
                final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
                        // 如果锁的计数器为0,则表示没有锁。
            if (c == 0) {
                            //  compareAndSetState方法实际调用的是unsafe.compareAndSwapInt(this, stateOffset, expect, update);
                // 直接操作的JVM。并给当前线程持有锁。
                                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
                        // 如果计数器不为0,但当前线程就是持有锁的线程。则锁的计数器增加。
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
                        // 如果计数器不为0,同时当前线程不是持有锁的线程。则加锁失败。
            return false;
        }
     }

  // 非公平所的实现器
  static final class NonfairSync extends Sync {

             // 加锁。
         final void lock() {
            if (compareAndSetState(0, 1)) //非公平加锁
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1); // 如果加锁不成功,则放入队列
        }

          // 试着加锁
          protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

    }

    // 公平锁
    static final class FairSync extends Sync {

             // 加锁,队列
         final void lock() {
            acquire(1);
        }

                // 试着加锁
                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;
        }

    }

}    

AbstractQueuedSynchronizer源码

 // 存储队列锁的存储node.是一个双向的链表结构。
 static final class Node {
   // 前一个node
   volatile Node prev;
     // 后一个node
     volatile Node next;
     // 该node所对应的线程
     volatile Thread thread;        
 }

 // 整个队列锁的第一个node.
 private transient volatile Node head;

 // 整个队列锁的第后个node.
 private transient volatile Node tail;

 // 锁的状态。计数器
 private volatile int state;

 // 加锁的关键点。通过navtive 方法unsafe直接操作CPU。
 protected final boolean compareAndSetState(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
 }

总结

Lock这种以类的方式来实现锁的机制。
优点:
1.加锁和释放锁独立,可以分开来控制。
2.tryLock的方法可以尝试加锁,不会像sychnorized一致阻塞。
3.实现了公平锁和非公平锁。sychnorized只能是非公平锁。

缺点:
1.增加了代码的复杂度。
2.相比sychnorized的自动加锁和释放锁,Lock需要手动,容易忘记,从而出现重大的隐患。

经过JDK的不断更新,sychnorized与lock的性能相差不大,官方建议使用sychnorized方法加锁。

以上是关于锁之ReentrantLock的主要内容,如果未能解决你的问题,请参考以下文章

Java锁之重入锁(Reentrantlock)原理,公平锁与非公平锁

Java并发程序设计(13)并发锁之读写锁

Java并发程序设计(16)并发锁之条件变量

ReentrantLock 源码分析

多线程编程-- part5.1 互斥锁之公平锁-释放锁

多线程编程-- part5.1 互斥锁之公平锁-获取锁