ITPub博客

首页 > 应用开发 > Java > Jdk1.6 JUC源码解析(7)-locks-ReentrantLock

Jdk1.6 JUC源码解析(7)-locks-ReentrantLock

Java 作者:壹頁書 时间:2015-11-13 00:29:34 0 删除 编辑
转自 大飞的博客
http://brokendreams.iteye.com/blog/2250883

Jdk1.6 JUC源码解析(7)-locks-ReentrantLock

作者:大飞


功能简介:
  • Java代码层面提供的锁机制,可做为Synchronized(jvm内置)的替代物,和Synchronized一样都是可重入的。
  • 与Synchronized相比较而言,ReentrantLock有以下优势:支持公平/非公平锁、支持可中断的锁、支持非阻塞的tryLock(可超时)、支持锁条件、可跨代码块使用(一个地方加锁,另一个地方解锁),总之比Synchronized更加灵活。但也有缺点,比如锁需要显示解锁、无法充分享用JVM内部性能提升带来的好处等等。
源码分析:
  • ReentrantLock实现了Lock接口,先来看下这个接口:
Java代码  
  1. public interface Lock {  
  2.     /** 
  3.      * 获取锁,如果锁无法获取,当前线程被阻塞,直到锁可以获取并获取成功为止。 
  4.      */  
  5.     void lock();  
  6.     /** 
  7.      * 在当前线程没有被中断的情况下获取锁。 
  8.      * 
  9.      * 如果获取成功,方法结束。 
  10.      * 
  11.      * 如果锁无法获取,当前线程被阻塞,直到下面情况发生: 
  12.      * 
  13.      * 1.当前线程(被唤醒后)成功获取锁。 
  14.      * 2.当前线程被其他线程中断。 
  15.      */  
  16.     void lockInterruptibly() throws InterruptedException;  
  17.     /** 
  18.      * 如果当前锁是可用的,获取锁。 
  19.      * 
  20.      * 获取成功后,返回true。 
  21.      * 如果当前锁不可用,返回false。 
  22.      */  
  23.     boolean tryLock();  
  24.     /** 
  25.      * 如果锁在给定超时时间内可用,并且当前线程没有被中断,那么获取锁。 
  26.      * 
  27.      * 如果锁可用,获取锁成功并返回true。 
  28.      *  
  29.      * 如果锁无法获取,当前线程被阻塞,直到下面情况发生: 
  30.      * 
  31.      * 1.当前线程(被唤醒后)成功获取锁。 
  32.      * 2.当前线程被其他线程中断。 
  33.      * 3.指定的等待时间超时。 
  34.      */  
  35.     boolean tryLock(long time, TimeUnit unit) throws InterruptedException;  
  36.     /** 
  37.      * 释放锁。 
  38.      */  
  39.     void unlock();  
  40.     /** 
  41.      * 返回一个和当前锁实例相关联的条件。 
  42.      * 
  43.      * 当前线程必须首先获取锁后才能在锁条件上等待。 
  44.      * 一个Condition的await()方法调用会在等待之前自动释放锁,在等待结束 
  45.      * 前重新获取锁。 
  46.      */  
  47.     Condition newCondition();  
  48. }  



  • 之前分析AQS的时候提到过,基于AQS构建的同步机制都会使用内部帮助类继承AQS的方式构建,看下ReentrantLock中的同步机制:
Java代码  
  1. //内部同步机制的引用。  
  2. private final Sync sync;  
  3. /** 
  4.  * 这个锁实现的基本同步控制机制,下面会提供公平和非公平版本的子类。 
  5.  * 利用AQS的state来表示锁持有(重入)的次数。. 
  6.  */  
  7. static abstract class Sync extends AbstractQueuedSynchronizer {  
  8.     private static final long serialVersionUID = -5179523762034025860L;  
  9.     /** 
  10.      * Performs {@link Lock#lock}. The main reason for subclassing 
  11.      * is to allow fast path for nonfair version. 
  12.      */  
  13.     abstract void lock();  
  14.     /** 
  15.      * 方法用来支持非公平的tryLock  
  16.      */  
  17.     final boolean nonfairTryAcquire(int acquires) {  
  18.         final Thread current = Thread.currentThread();  
  19.         int c = getState();  
  20.         if (c == 0) {  
  21.             //如果当前没有任何线程获取锁(锁可用),尝试设置state。  
  22.             if (compareAndSetState(0, acquires)) {  
  23.                 //如果设置成功,将当前线程信息设置到AQS中(所有权关联)。   
  24.                 setExclusiveOwnerThread(current);  
  25.                 return true;  
  26.             }  
  27.         }  
  28.         //如果锁已经被持有,那么判断一下持有锁的线程是否为当前线程。  
  29.         else if (current == getExclusiveOwnerThread()) {  
  30.             //如果是当前线程在持有锁,那么这里累计一下重入次数。  
  31.             int nextc = c + acquires;  
  32.             if (nextc < 0// overflow  重入次数最大不能超过int的最大值  
  33.                 throw new Error("Maximum lock count exceeded");  
  34.             //设置到AQS的state中  
  35.             setState(nextc);  
  36.             return true;  
  37.         }  
  38.         //如果锁已经被持有,且持有线程不是当前线程,返回false。  
  39.         return false;  
  40.     }  
  41.     protected final boolean tryRelease(int releases) {  
  42.         //释放时,这里要减去重入次数。  
  43.         int c = getState() - releases;  
  44.         //判断控制权关系是否正确。  
  45.         if (Thread.currentThread() != getExclusiveOwnerThread())  
  46.             throw new IllegalMonitorStateException();  
  47.         boolean free = false;  
  48.         if (c == 0) {  
  49.             //如果当前线程完全释放了锁(重入次数为0)  
  50.             free = true;  
  51.             //解除所有权关系。  
  52.             setExclusiveOwnerThread(null);  
  53.         }  
  54.         //设置重入次数。  
  55.         setState(c);  
  56.         //返回是否释放成功(或者说是否完全释放)。  
  57.         return free;  
  58.     }  
  59.     protected final boolean isHeldExclusively() {  
  60.         // While we must in general read state before owner,  
  61.         // we don't need to do so to check if current thread is owner  
  62.         return getExclusiveOwnerThread() == Thread.currentThread();  
  63.     }  
  64.     final ConditionObject newCondition() {  
  65.         return new ConditionObject();  
  66.     }  
  67.     // Methods relayed from outer class  
  68.     final Thread getOwner() {  
  69.         return getState() == 0 ? null : getExclusiveOwnerThread();  
  70.     }  
  71.     final int getHoldCount() {  
  72.         return isHeldExclusively() ? getState() : 0;  
  73.     }  
  74.     final boolean isLocked() {  
  75.         return getState() != 0;  
  76.     }  
  77.     /** 
  78.      * Reconstitutes this lock instance from a stream. 
  79.      * @param s the stream 
  80.      */  
  81.     private void readObject(java.io.ObjectInputStream s)  
  82.         throws java.io.IOException, ClassNotFoundException {  
  83.         s.defaultReadObject();  
  84.         setState(0); // reset to unlocked state  
  85.     }  
  86. }  


       接下来先看一下非公平版本的子类:

Java代码  
  1. /** 
  2.  * Sync object for non-fair locks 
  3.  */  
  4. final static class NonfairSync extends Sync {  
  5.     private static final long serialVersionUID = 7316153563782823691L;  
  6.     /** 
  7.      * Performs lock.  Try immediate barge, backing up to normal 
  8.      * acquire on failure. 
  9.      */  
  10.     final void lock() {  
  11.         //这里首先尝试一个短代码路径,直接CAS设置state,尝试获取锁。  
  12.         //相当于一个插队的动作(可能出现AQS等待队列里有线程在等待,但当前线程竞争成功)。  
  13.         if (compareAndSetState(01))  
  14.             setExclusiveOwnerThread(Thread.currentThread());  
  15.         else   
  16.             acquire(1);//如果CAS失败,调用AQS的独占请求方法。  
  17.     }  
  18.     protected final boolean tryAcquire(int acquires) {  
  19.         //调用上面父类的nonfairTryAcquire方法。  
  20.         return nonfairTryAcquire(acquires);  
  21.     }  
  22. }  


       再来先看一下公平版本的子类:

Java代码  
  1. /** 
  2.  * Sync object for fair locks 
  3.  */  
  4. final static class FairSync extends Sync {  
  5.     private static final long serialVersionUID = -3000897897090466540L;  
  6.     final void lock() {  
  7.         acquire(1);  
  8.     }  
  9.     /** 
  10.      * 公平版本的tryAcquire。  
  11.      * 只有在递归(重入)或者同步队列中没有其他线程 
  12.      * 或者当前线程是等待队列中的第一个线程时才准许访问。 
  13.      */  
  14.     protected final boolean tryAcquire(int acquires) {  
  15.         final Thread current = Thread.currentThread();  
  16.         int c = getState();  
  17.         if (c == 0) {  
  18.             if (!hasQueuedPredecessors() &&  
  19.                 compareAndSetState(0, acquires)) { //如果当前锁可用,且同步等待队列中没有其他线程,那么尝试设置state  
  20.                 setExclusiveOwnerThread(current); //如果设置成功,相当于获取锁成功,设置所有权关系。  
  21.                 return true;  
  22.             }  
  23.         }  
  24.         else if (current == getExclusiveOwnerThread()) {  
  25.             //如果当前线程已经持有该锁,那么累计重入次数。  
  26.             int nextc = c + acquires;  
  27.             if (nextc < 0)  
  28.                 throw new Error("Maximum lock count exceeded");  
  29.             setState(nextc);  
  30.             return true;  
  31.         }  
  32.         return false;  
  33.     }  
  34. }  


       小总结一下:
 
       非公平版的锁-加锁操作
              1.当前线程首先会无条件的执行一个CAS操作来获取锁,如果CAS操作成功,获取锁成功。
              2.如果第1步没成功,当前会检查锁是否被其他线程持有,也就是锁是否可用。
              3.如果没有其他线程持有锁,会以CAS的方式尝试获取锁,如果CAS操作成功,获取锁成功。
              4.如果有其他线程持有锁,会判断一下持有锁的线程是否为当前线程,如果是当前线程,重入次数+1,获取锁成功。
              5.根据AQS的分析,上述2、3、4步会执行多次,如果最终获取锁失败,当前线程会被阻塞,等待其他线程执行解锁操作将其唤醒。
 
       公平版的锁-加锁操作
              1.当前线程首先会检查锁是否被其他线程持有,并且当前同步等待队列里有没有其他线程在等待。
              2.如果没有其他线程持有锁,且同步等待队列里没有其他线程,会以CAS的方式尝试获取锁,如果CAS操作成功,获取锁成功。
              3.如果有其他线程持有锁,会判断一下持有锁的线程是否为当前线程,如果是当前线程,重入次数+1,获取锁成功。
              4.根据AQS的分析,上述1、2、3步会执行多次,如果最终获取锁失败,当前线程会被阻塞,等待其他线程执行解锁操作将其唤醒。
 
       非公平版和公平版锁的解锁操作一样
              1.当前线程首先将锁重入次数减1(AQS的state),如果减1后结果为0,将当前同步器的线程信息置空,并唤醒同步等待队列中队头的等待线程。
              2.如果第1步中,重入次数减1后结果不为0(说明当前线程还持有当前锁),方法结束。
 
  • 有了内部的基础同步机制,ReentrantLock的实现就很简单了,直接看代码:
Java代码  
  1. /** 
  2.  * 默认情况下构建非公平锁。 
  3.  */  
  4. public ReentrantLock() {  
  5.     sync = new NonfairSync();  
  6. }  
  7. /** 
  8.  * 根据给定的公平策略生成相应的实例。 
  9.  * 
  10.  * @param fair {@code true} if this lock should use a fair ordering policy 
  11.  */  
  12. public ReentrantLock(boolean fair) {  
  13.     sync = (fair)? new FairSync() : new NonfairSync();  
  14. }  
  15.   
  16. public void lock() {  
  17.     sync.lock();  
  18. }  
  19.   
  20. public void lockInterruptibly() throws InterruptedException {  
  21.     sync.acquireInterruptibly(1);  
  22. }  
  23.   
  24. public boolean tryLock() {  
  25.     return sync.nonfairTryAcquire(1);  
  26. }  
  27.   
  28. public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {  
  29.     return sync.tryAcquireNanos(1, unit.toNanos(timeout));  
  30. }  
  31.   
  32. public void unlock() {  
  33.     sync.release(1);  
  34. }  
  35.   
  36. public Condition newCondition() {  
  37.     return sync.newCondition();  
  38. }  


       最后看一下一些支持监测的方法:

Java代码  
  1. /** 
  2.  * 获取当前线程的对当前锁的持有(重入)次数。 
  3.  */  
  4. public int getHoldCount() {  
  5.     return sync.getHoldCount();  
  6. }  
  7. /** 
  8.  * 判断当前锁是否被当前线程持有。 
  9.  */  
  10. public boolean isHeldByCurrentThread() {  
  11.     return sync.isHeldExclusively();  
  12. }  
  13. /** 
  14.  * 判断当前锁是否被(某个线程)持有。 
  15.  */  
  16. public boolean isLocked() {  
  17.     return sync.isLocked();  
  18. }  
  19. /** 
  20.  * 当前锁是否为公平锁。 
  21.  */  
  22. public final boolean isFair() {  
  23.     return sync instanceof FairSync;  
  24. }  
  25. /** 
  26.  * 获取持有当前锁的线程。 
  27.  */  
  28. protected Thread getOwner() {  
  29.     return sync.getOwner();  
  30. }  
  31. /** 
  32.  * 判断是否有线程在当前锁的同步等待队列中等待。  
  33.  */  
  34. public final boolean hasQueuedThreads() {  
  35.     return sync.hasQueuedThreads();  
  36. }  
  37. /** 
  38.  * 判断给定的线程是否在当前锁的同步等待队列中等待。 
  39.  */  
  40. public final boolean hasQueuedThread(Thread thread) {  
  41.     return sync.isQueued(thread);  
  42. }  
  43. /** 
  44.  * 获取当前锁的同步等待队列中的等待线程(估计)数量。 
  45.  */  
  46. public final int getQueueLength() {  
  47.     return sync.getQueueLength();  
  48. }  
  49. /** 
  50.  * 获取当前锁的同步等待队列中等待的线程。 
  51.  */  
  52. protected Collection getQueuedThreads() {  
  53.     return sync.getQueuedThreads();  
  54. }  
  55. /** 
  56.  * 判断是否有线程在给定条件的条件等待队列上等待。 
  57.  */  
  58. public boolean hasWaiters(Condition condition) {  
  59.     if (condition == null)  
  60.         throw new NullPointerException();  
  61.     if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))  
  62.         throw new IllegalArgumentException("not owner");  
  63.     return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);  
  64. }  
  65. /** 
  66.  * 获取给定条件的条件等待队列中等待线程的(估计)数量。 
  67.  */  
  68. public int getWaitQueueLength(Condition condition) {  
  69.     if (condition == null)  
  70.         throw new NullPointerException();  
  71.     if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))  
  72.         throw new IllegalArgumentException("not owner");  
  73.     return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);  
  74. }  
  75. /** 
  76.  * 获取给定条件的条件等待队列中等待线程。 
  77.  */  
  78. protected Collection getWaitingThreads(Condition condition) {  
  79.     if (condition == null)  
  80.         throw new NullPointerException();  
  81.     if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))  
  82.         throw new IllegalArgumentException("not owner");  
  83.     return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);  
  84. }  


       ReentrantLock的代码解析完毕!



       参见:Jdk1.6 JUC源码解析(6)-locks-AbstractQueuedSynchronizer


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29254281/viewspace-1835220/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2013-10-19

  • 博文量
    621
  • 访问量
    6128375