Java8 ReentrantLock(一) 源码解析

 目录

一、AbstractQueuedSynchronizer

1、定义

2、Unsafe objectFieldOffset和staticFieldOffset

3、Node

二、ReentrantLock

1、acquireQueued

2、lock

3、lockInterruptibly

4、tryLock

5、unlock

 6、其他方法实现总结


       ReentrantLock表示一个可重入的互斥锁,跟synchronized语义基本一致,还扩展了部分功能。当某个线程调用lock方法返回后就表示该线程占有了该锁,如果再次调用lock方法就会立即返回,可通过isHeldByCurrentThread或者getHoldCount方法来判断是否占有该锁。ReentrantLock默认是非公平锁,即哪个线程获取锁是完全随机的,长时间等待的线程不会优先获取锁,如果将构造方法的boolean参数fairness设置为true,则变成了公平锁,该参数默认为false,公平锁可保证长时间等待的线程优先获取锁,但是会导致并发情况下应用程序的吞吐量大幅降低,另外公平锁不能保证系统进程调度的公平,有可能某个线程获取了锁但是没有被系统进程调度分配CPU时间片。ReentrantLock除了实现Lock接口外,还定义了很多public方法来获取锁内部的状态,对于锁使用情况的监控非常有用。ReentrantLock在反序列化的时候都是没有被锁定的状态,无论其在序列化时是否是锁定状态的。ReentrantLock允许同一个线程最多重复lock 2147483647次,超过这个次数限制就会报错。

一、AbstractQueuedSynchronizer

      AbstractQueuedSynchronizer提供了一个实现互斥锁,信号量等同步工具的基础框架,基于FIFO等待队列和一个原子更新的表示状态的int值实现的。AbstractQueuedSynchronizer已经实现了线程阻塞以及操作等待队列的相关方法,子类只需定义如何去修改状态,获取和释放同步器时的状态的方法即可,主要操作状态时必须原子的,可借助getState,setState和compareAndSetState等方法。

     AbstractQueuedSynchronizer本身并不没有实现任何Lock相关的接口,但是提供了acquireQueued / acquireInterruptibly等方法,子类可以据此实现Lock接口。AbstractQueuedSynchronizer本身同时支持互斥模式和共享模式,但是该类本身并不关注其中的差异,而是由子类决定,通常情况下子类只支持一种模式,这时不需要定义方法来支持另一种不支持的模式。

     AbstractQueuedSynchronizer定义了一个内部类ConditionObject,该类是Condition接口的实现类,子类可以利用该类实现互斥模式。AbstractQueuedSynchronizer本身的方法并不会创建一个ConditionObject实例,他的具体语义完全由子类同步器的实现决定。

    AbstractQueuedSynchronizer的序列化实现只存储了一个状态值,没有存储等待的线程队列,因此反序列化的时候等待的线程队列就是空的,子类如果有这方面需要的话,必须要重写readObject方法。

    子类继承AbstractQueuedSynchronizer时,必须实现如下方法:

    实现这些方法必须是线程安全的,代码比较短且是非阻塞的,AbstractQueuedSynchronizer中其他的方法都是final的,不允许被子类改写。

1、定义

     AbstractQueuedSynchronizer继承自AbstractOwnableSynchronizer,该类只有一个属性,private transient Thread exclusiveOwnerThread; 表示占有当前同步器的线程,并且定义了该属性对应的get/set方法,如下:

    AbstractQueuedSynchronizer有两个内部类,ConditionObject和Node,前者是public的,后者是默认的包内访问并且static final的,前者用于实现互斥模式,后者表示等待队列中的一个节点,后面会详细讲解这两个内部类的实现。除此之外定义的属性如下:

  • private transient volatile Node head;  //等待获取锁的链表头,该链表简称同步链表,head和tail都是惰性初始化
  • private transient volatile Node tail;  //等待获取锁的链表尾
  • private volatile int state;  //状态值,主要用于实现锁重入,state等于0表示未被占用,大于0表示累计获取锁的次数
  •  private static final Unsafe unsafe = Unsafe.getUnsafe();
  •  private static final long stateOffset;  //上述state属性在AbstractQueuedSynchronizer实例中的内存偏移量
  •  private static final long headOffset; //同上,head属性的偏移量
  •  private static final long tailOffset;  //同上,tail属性的偏移量
  •  private static final long waitStatusOffset; //Node的waitStatus属性在Node实例中的内存偏移量
  •  private static final long nextOffset;//Node的next属性在Node实例中的内存偏移量

上述static属性都是通过static代码块和Unsafe的方法实现,如下:

2、Unsafe objectFieldOffset和staticFieldOffset

      objectFieldOffset是一个本地方法,用来获取实例字段在实例内存中相对于实例地址的偏移量,可据此算出存储该属性的内存地址,用于原子的修改该属性。与之类似的,有一个staticFieldOffset,用来获取静态字段的内存偏移量,其底层实现如下:

//获取实例字段偏移量
UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset(JNIEnv *env, jobject unsafe, jobject field))
  UnsafeWrapper("Unsafe_ObjectFieldOffset");
  
  return find_field_offset(field, 0, THREAD);
UNSAFE_END

//还有一个获取静态字段偏移量的方法
UNSAFE_ENTRY(jlong, Unsafe_StaticFieldOffset(JNIEnv *env, jobject unsafe, jobject field))
  UnsafeWrapper("Unsafe_StaticFieldOffset");
  return find_field_offset(field, 1, THREAD);
UNSAFE_END

jint find_field_offset(jobject field, int must_be_static, TRAPS) {
  if (field == NULL) {
    //field为空,抛出异常
    THROW_0(vmSymbols::java_lang_NullPointerException());
  }
  
  //解析出java_lang_reflect_Field实例oop
  oop reflected   = JNIHandles::resolve_non_null(field);
  //获取klass
  oop mirror      = java_lang_reflect_Field::clazz(reflected);
  Klass* k      = java_lang_Class::as_Klass(mirror);
  //获取slot属性,slot表示该字段是第几个字段
  int slot        = java_lang_reflect_Field::slot(reflected);
  //获取字段修饰符
  int modifiers   = java_lang_reflect_Field::modifiers(reflected);

  if (must_be_static >= 0) {
    //是否静态字段,如果是really_is_static就等于1
    int really_is_static = ((modifiers & JVM_ACC_STATIC) != 0);
    if (must_be_static != really_is_static) {
      THROW_0(vmSymbols::java_lang_IllegalArgumentException());
    }
  }
  //获取字段偏移量
  int offset = InstanceKlass::cast(k)->field_offset(slot);
  return field_offset_from_byte_offset(offset);
}

//获取slot属性
int java_lang_reflect_Field::slot(oop reflect) {
  assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
  return reflect->int_field(slot_offset);
}

inline jlong field_offset_from_byte_offset(jlong byte_offset) {
  return byte_offset;
}

3、Node

      Node表示等待队列中的一个节点,其包含的属性如下:

  • volatile int waitStatus; //当前Node节点的状态
  • volatile Node prev;  //前一个Node节点
  • volatile Node next;  //下一个Node节点
  • volatile Thread thread; //关联的线程
  • Node nextWaiter;  //用来构造一个在Condition上等待即调用await方法的Node节点链表,如果nextWaiter是一个常量值SHARED,则表示当前Node是共享模式

       Node定义了以下的常量值:

  • static final Node SHARED = new Node();  //表示共享模式,给nextWaiter复制
  • static final Node EXCLUSIVE = null; //表示互斥模式
  • static final int CANCELLED =  1;//以下四个都是状态值,给waitStatus赋值,CANCELLED表示一个无效节点,对应的线程通常会退出
  • static final int SIGNAL    = -1;  //表示当前节点的下一个节点对应的线程需要被唤醒
  • static final int CONDITION = -2; //表示关联的线程正在某个Condition上等待,当该Condition的sigal或者sigalAll方法被调用时,该节点的状态会变成0,即初始状态
  • static final int PROPAGATE = -3; //表示传播状态

       Node定义的方法比较简单,如下:

 

isShared方法根据 nextWaiter的属性值判断是否共享模式,predecessor返回当前节点的前一个节点,如果为空则抛出异常。

AbstractQueuedSynchronizer的方法比较庞杂,后面结合具体的应用场景分析。

二、ReentrantLock

       ReentrantLock的方法实现都是基于其私有属性Sync sync,Sync的类继承关系如下:

FairSync和NonfairSync都只提供了lock和tryAcquire方法的实现,其他实现都是公用父类Sync实现,如下:

默认的非公平锁实现就是NonfairSync,公平锁实现就是FairSync,构造方法的入参fair为true,则sync初始化为FairSync,否则是NonfairSync,参考构造方法的实现如下:

下面就来详细探讨各方法的实现细节以及公平锁和非公平锁下的实现差异。

1、acquireQueued

     acquireQueued用于给node节点关联的线程抢占锁,如果在node前面还有其他等待的线程或者node对应的节点抢占失败,则进入被阻塞,进入休眠状态,等待被唤醒;如果被唤醒了,抢占锁依然失败,则继续被阻塞,进入休眠状态;如果上述过程有异常则将node置为CANCELLED,关联的thread置为null,并将其从链表中移除。如果线程被唤醒是因为被中断则返回true,否则返回false。

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                //获取node的前一个节点
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    //如果前一个节点是head,即当前节点是链表中第一个添加的节点
                    //tryAcquire为true,表示尝试获取锁成功,将node置为head
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //如果p不等于head,说明前面还有等待获取锁的线程
                //如果p等于head但是获取锁失败,说明有其他线程并发抢占锁
                //如果上述的if条件不成功,则shouldParkAfterFailedAcquire多执行几次必定返回true
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())//parkAndCheckInterrupt返回true表示线程被中断了
                    interrupted = true;
                //被唤醒后继续下一次循环,如果抢占锁失败,则继续进入parkAndCheckInterrupt方法阻塞当前线程
            }
        } finally {
            //上述代码执行过程中出现异常时,进入此逻辑
            if (failed)
                cancelAcquire(node);
        }
    }

//如果返回true,表示当前节点node需要被阻塞,通常用于for循环中
//如果p是初始的空节点,则第一遍for循环shouldParkAfterFailedAcquire返回false,第二遍返回true
//如果是正常节点且p的waitStatus大于0,第一遍for循环shouldParkAfterFailedAcquire返回false,会将中间的waitStatus大于0的节点都移除,第二遍循环时如果上一个节点的
//waitStatus就是SIGNAL则返回true,否则将其修改成SIGNAL;第三次循环判断是SIGNAL返回true
//如果是正常节点且p的waitStatus小于0,如果waitStatus就是SIGNAL则返回true,否则将其修改成SIGNAL;第二次循环判断是SIGNAL返回true
//综上,无论什么节点,最多循环三次shouldParkAfterFailedAcquire肯定返回true
 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
            //往前遍历找到一个waitStatus不大于0的节点,将中间waitStatus小于0的节点都移除
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            //waitStatus 必须是0 or PROPAGATE,将其状态原子的置为SIGNAL
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

 private final boolean parkAndCheckInterrupt() {
        //将当前线程阻塞
        LockSupport.park(this);
        //线程被唤醒,判断是否被中断了
        return Thread.interrupted();
    }

private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;

        node.thread = null;

        //跳过所有已经被cancelled的节点,将node的prev设置为第一个非cancelled的节点
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;

        Node predNext = pred.next;

        //修改状态
        node.waitStatus = Node.CANCELLED;

        //如果node是tail,最后一个节点,原子的修改tail为pred
        if (node == tail && compareAndSetTail(node, pred)) {
            //将pred的next属性置为null
            compareAndSetNext(pred, predNext, null);
        } else {
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                //node的前一个节点不是head,也不等于tail,应该位于众佳丽
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    //原子的修改pred的next属性为next节点,即移除了node
                    compareAndSetNext(pred, predNext, next);
            } else {
                //如果pred等于head
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }

    private void unparkSuccessor(Node node) {
        
        int ws = node.waitStatus;
        if (ws < 0)
            //将其原子的修改成0
            compareAndSetWaitStatus(node, ws, 0);

        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            //从tail往前遍历找到位于node后的最前面的一个waitStatus不大于0的节点
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }//如果if为false就是唤醒node的下一个节点,否则唤醒位于node后的最前面的一个waitStatus不大于0的节点
        if (s != null)
            //唤醒s对应的线程
            LockSupport.unpark(s.thread);
    }

2、lock

    lock方法用于获取锁,如果当前线程已经获取锁则立即返回,如果其他线程占有了该锁,则当前线程会被阻塞,处于休眠状态,当占有该锁的线程释放锁时会唤醒当前线程去抢占锁,如果抢占成功则返回,否则继续休眠。

 public void lock() {
        sync.lock();
    }

 final void lock() {
            //如果state是0,则将其原子的设置为1,设置成功将当前线程设置为锁的占有线程
            //state是0表示该锁没有被占用 
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

public final void acquire(int arg) {
        if (!tryAcquire(arg) && //如果尝试获取锁失败就执行下面的acquireQueued方法,如果获取成功则直接返回
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //acquireQueued方法会将当前线程阻塞,直到成功获取锁,如果该方法返回true,表示线程是因为中断被唤醒的
            //将当前线程中断,实际可能已经是中断状态了
            selfInterrupt();
    }

//如果尝试占用成功返回true,否则返回false
 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) {
                //state为0,锁未被占用
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                //当前线程已经占用了锁
                int nextc = c + acquires;
                if (nextc < 0) // 超过int的最大值了,变成负值
                    throw new Error("Maximum lock count exceeded");
                //重置state,    
                setState(nextc);
                return true;
            }
            return false;
        }

//如果链表为空则使用一个空的Node初始化链表,否则将目标节点插入到tail后面并修改tail,最后返回新创建的节点
 private Node addWaiter(Node mode) {
        //创建一个新的节点
        Node node = new Node(Thread.currentThread(), mode);
        Node pred = tail;
        if (pred != null) {
            //tail不为空,即链表不为空,则将新节点插入到tail的后面
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                //如果成功将tail修改成node
                pred.next = node;
                return node;
            }
            //如果tail修改失败则进入下面的enq方法,说明有多个线程子啊修改tail
        }
        enq(node);
        return node;
    }

//如果链表为空则使用一个空的Node初始化链表,否则不断循环将目标节点插入到tail后面,并修改tail,直到tail修改成功为止
private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { //链表为空,将tail和head初始化成跟一个空节点
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                //将node插入到tail的后面,如果修改tail失败则通过for循环重试,直到修改成功为止
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

 static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }

  上述实现是非公平锁的,公平锁的实现如下:

final void lock() {
  //跟非公平锁相比少了一个compareAndSetState,即不会尝试抢占锁
  acquire(1);
}

protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() && //跟非公平锁相比就多了这一个判断,如果有等待获取锁的线程,则直接返回false,不去尝试抢占了
                    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;
        }

//如果有待处理的节点,则返回true,如果链表为空则返回false
public final boolean hasQueuedPredecessors() {
        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());
    }

公平锁和非公平锁的实现基本是一样的,只有lock方法和tryAcquire方法的实现不一样,公平锁下一个新的线程不会与等待队列中的线程竞争锁,而是直接加入到等待队列中,先加入队列的线程优先获取锁;而非公平锁下,一个新的线程会与等待队列中的线程竞争锁,没有新线程竞争的时候才是先加入队列的线程优先获取锁,这样就可能等待队列中的线程一直无法获取锁,出现锁饥饿等待的情形。

3、lockInterruptibly

      lock方法被中断后还会继续抢占锁直到抢占成功为止,lockInterruptibly被中断后会抛出异常,并清除中断标识;如果没有被中断,则会一直阻塞直到抢占成功为止。其实现如下:

public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        //acquire方法不会检查是否中断状态    
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }

 //跟acquireQueued方法的实现一致,就一点区别,如果是因为中断被唤醒,前者会抢占锁,后者会抛出异常
 private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                 //parkAndCheckInterrupt方法返回线程是否中断时,如果线程是中断的则返回true,并且将中断标识清除,即置为false
                    parkAndCheckInterrupt())
                    //如果因为中断被唤醒则抛出异常
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }    

注意所谓的中断,并不是中断线程的正常执行,而是中断线程的休眠或者阻塞,让他恢复正常执行,同时将中断标识设置为true。测试用例如下:

@Test
    public void test() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    lock.lock();
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        b.start();
        while (b.isAlive()){
            b.interrupt();
            System.out.println("interrupted->"+b.isInterrupted());
            Thread.sleep(200);
        }
    }

输出如下:

//多次中断,不会抛出异常,继续获取锁,直到获取成功为止
interrupted->true
interrupted->true
//被中断后,如果thread b被唤醒了且先于main线程执行,则会把中断标识清除
//main线程再获取就是false
interrupted->false
interrupted->true
interrupted->true
interrupted->true
//进入sleep,被中断后抛出异常
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at synchronizedTest.ReentrantLockTest$2.run(ReentrantLockTest.java:32)
	at java.lang.Thread.run(Thread.java:748)

 如果把上述用例中thread b的lock方法改成lockInterruptibly,则输出如下:

interrupted->true
//被中断后抛出异常
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at synchronizedTest.ReentrantLockTest$2.run(ReentrantLockTest.java:31)
	at java.lang.Thread.run(Thread.java:748)
//因为没有获取锁就执行unlock方法,所以抛出异常
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
	at synchronizedTest.ReentrantLockTest$2.run(ReentrantLockTest.java:36)
	at java.lang.Thread.run(Thread.java:748)

为了避免上述的IllegalMonitorStateException异常,unlock方法解锁时应该通过isHeldByCurrentThread判断当前线程是否持有锁,如果是通过lock方法加锁则不需要了,如下:

@Test
    public void test() throws Exception {
        ReentrantLock lock=new ReentrantLock();
        Thread a=new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    lock.lock();
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        });
        a.start();
        Thread b=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lockInterruptibly();
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if(lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            }
        });
        b.start();
        while (b.isAlive()){
            b.interrupt();
            System.out.println("interrupted->"+b.isInterrupted());
            Thread.sleep(200);
        }
    }

4、tryLock

     tryLock方法有两个版本,不带参数的实现和非公平锁下tryAcquire方法的实现一致,会尝试获取锁,如果获取失败则直接返回false,如果抢占成功或者当前线程本身是持有锁的则直接返回true。带等待时间的版本,会在指定的时间内尝试获取锁,如果当前线程已经是中断的或者在等待过程中被中断都会抛出InterruptedException异常,否则会尝试获取锁直到等待的时间结束,如果时间结束未获取锁则返回false,获取成功返回true。

//尝试获取锁,如果获取失败则直接返回
public boolean tryLock() {
        //跟非公平锁下tryAcquire方法的实现一致
    return sync.nonfairTryAcquire(1);
}

//尝试获取锁,如果获取失败则最多等待指定的时间
public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            //如果被中断抛出异常
            throw new InterruptedException();
        //tryAcquire尝试获取锁,如果获取成功则直接返回true,获取失败返回false,进入doAcquireNanos
        //doAcquireNanos会在指定的时间范围内尝试获取锁,如果被中断则抛出异常
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }

 private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        //计算等待的截止时间    
        final long deadline = System.nanoTime() + nanosTimeout;
        //添加一个新的等待节点
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                //计算剩余的等待时间
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                //如果需要阻塞,则剩余时间大于spinForTimeoutThreshold,则将其阻塞
                //如果小於则直接for循环,即自旋    
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                //线程被唤醒了,检查是否被中断,如果是则抛出异常    
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                //如果出现异常比如上面抛出中断异常,将node的状态置为cancel
                cancelAcquire(node);
        }
    }

  5、unlock

       unlock用于释放锁,会将state减1,如果state等于0说明之前锁重入时调用的lock方法,都调用了对应的unlock方法,否则说明还有未调用unlock方法的,则直接返回false。如果state等于0,则唤醒head的下一个节点对应的线程并返回true,该线程被唤醒后会将该节点重置为head。

public void unlock() {
        sync.release(1);
    }

public final boolean release(int arg) {
        //tryRelease会更新state,如果state等于0则返回true,表示需要释放锁,
        //如果不等于0,说明还有重入的锁未调用unlock方法,返回false
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                //唤醒head的下一个节点对应的等待线程
                //该线程被唤醒后会将该节点重置为head
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            //如果当前线程没有获取锁,则抛出异常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                //c等于0表示所有重入的锁都已经释放了,返回true
                free = true;
                //将当前锁的占有线程设置为null
                setExclusiveOwnerThread(null);
            }
            //设置state
            setState(c);
            return free;
        }

 6、其他方法实现总结

      其他方法的实现就比较简单了,这里做简单的总结:

  • getHoldCount:如果是当前线程占有锁则返回state属性,否则返回0
  • getOwner:获取占有当前锁的线程,如果state为0,则表示未被占有,返回null
  • getQueuedThreads:获取所有等待的线程列表,从tail开始往前遍历,将所有节点对应的Thread加入到List中,最后返回该List
  • getQueueLength:获取等待线程的数量,同样是从tail往前遍历,计数加1
  • hasQueuedThread:判断某个线程是否在等待链表中,从tail开始往前遍历,如果找到thread属性等于目标线程的节点则返回true
  • hasQueuedThreads:判断是否有等待的线程,即等待链表是否为空
  • isHeldByCurrentThread:判断当前线程是否占用锁,用占用锁的Thread与当前Thread比较即可
  • isLocked:判断当前锁是否被占有,如果state不等于0则返回true

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章