`
BrokenDreams
  • 浏览: 253988 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
68ec41aa-0ce6-3f83-961b-5aa541d59e48
Java并发包源码解析
浏览量:100157
社区版块
存档分类
最新评论

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

阅读更多

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

作者:大飞

 

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

 

 

  • 之前分析AQS的时候提到过,基于AQS构建的同步机制都会使用内部帮助类继承AQS的方式构建,看下ReentrantLock中的同步机制:
    //内部同步机制的引用。
    private final Sync sync;
    /**
     * 这个锁实现的基本同步控制机制,下面会提供公平和非公平版本的子类。
     * 利用AQS的state来表示锁持有(重入)的次数。.
     */
    static abstract class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;
        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();
        /**
         * 方法用来支持非公平的tryLock 
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //如果当前没有任何线程获取锁(锁可用),尝试设置state。
                if (compareAndSetState(0, acquires)) {
                    //如果设置成功,将当前线程信息设置到AQS中(所有权关联)。 
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //如果锁已经被持有,那么判断一下持有锁的线程是否为当前线程。
            else if (current == getExclusiveOwnerThread()) {
                //如果是当前线程在持有锁,那么这里累计一下重入次数。
                int nextc = c + acquires;
                if (nextc < 0) // overflow  重入次数最大不能超过int的最大值
                    throw new Error("Maximum lock count exceeded");
                //设置到AQS的state中
                setState(nextc);
                return true;
            }
            //如果锁已经被持有,且持有线程不是当前线程,返回false。
            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) {
                //如果当前线程完全释放了锁(重入次数为0)
                free = true;
                //解除所有权关系。
                setExclusiveOwnerThread(null);
            }
            //设置重入次数。
            setState(c);
            //返回是否释放成功(或者说是否完全释放)。
            return free;
        }
        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
        final ConditionObject newCondition() {
            return new ConditionObject();
        }
        // Methods relayed from outer class
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
        final boolean isLocked() {
            return getState() != 0;
        }
        /**
         * Reconstitutes this lock instance from a stream.
         * @param s the stream
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

 

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

    /**
     * Sync object for non-fair locks
     */
    final static 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() {
            //这里首先尝试一个短代码路径,直接CAS设置state,尝试获取锁。
            //相当于一个插队的动作(可能出现AQS等待队列里有线程在等待,但当前线程竞争成功)。
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else 
                acquire(1);//如果CAS失败,调用AQS的独占请求方法。
        }
        protected final boolean tryAcquire(int acquires) {
            //调用上面父类的nonfairTryAcquire方法。
            return nonfairTryAcquire(acquires);
        }
    }

 

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

    /**
     * Sync object for fair locks
     */
    final static class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        final void lock() {
            acquire(1);
        }
        /**
         * 公平版本的tryAcquire。 
         * 只有在递归(重入)或者同步队列中没有其他线程
         * 或者当前线程是等待队列中的第一个线程时才准许访问。
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) { //如果当前锁可用,且同步等待队列中没有其他线程,那么尝试设置state
                    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;
        }
    }

 

       小总结一下:
 
       非公平版的锁-加锁操作
              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的实现就很简单了,直接看代码:
    /**
     * 默认情况下构建非公平锁。
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    /**
     * 根据给定的公平策略生成相应的实例。
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = (fair)? new FairSync() : new NonfairSync();
    }

    public void lock() {
        sync.lock();
    }
    
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

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

    public Condition newCondition() {
        return sync.newCondition();
    }

 

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

    /**
     * 获取当前线程的对当前锁的持有(重入)次数。
     */
    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<Thread> 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<Thread> 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);
    }

  

       ReentrantLock的代码解析完毕!

 

 

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

 

 

 

分享到:
评论

相关推荐

    aspose-words-15.8.0-jdk1.6

    aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-15.8.0-jdk1.6aspose-words-...

    jdk-1.6-windows-64-01

    2部分: jdk-1.6-windows-64-01 jdk-1.6-windows-64-02

    okhttp3.8源码使用jdk1.6重新编译_okhttp3.8.0-jdk1.6.zip

    1.okhttp3.8源码使用jdk1.6重新编译,已集成了okio,在javaweb项目中使用,未在安卓项目中使用 2.okhttp3.8源码使用jdk1.6重新编译_okhttp3.8.0-jdk1.6.jar

    JDK 1.6 64位(jdk-6u45-windows-x64(1.6 64))

    下载的压缩包文件"jdk-6u45-windows-x64(1.6 64).exe"是Windows 64位系统的安装程序。安装过程中,用户需要选择安装路径,并设置环境变量,包括`JAVA_HOME`指向JDK的安装目录,`PATH`添加JDK的bin目录,确保系统可以...

    jdk1.6集成jjwt的问题

    2. **语法不兼容**:JJWT可能使用了Java 7或8的新语法,如Lambda表达式或方法引用,这些在JDK 1.6中不可用。 - **解决方案**:查找并替换使用了新语法的代码,或者使用不依赖这些特性的旧版JJWT。 3. **运行时...

    jdk-1.6-linux-64-3

    三部分: jdk-1.6-linux-64-1 jdk-1.6-linux-64-2 jdk-1.6-linux-64-3

    java-jdk1.6-jdk-6u45-windows-x64.zip

    1. 解压缩"java-jdk1.6-jdk-6u45-windows-x64.zip"文件,这将释放出"jdk-6u45-windows-x64.exe"可执行文件。 2. 双击运行"jdk-6u45-windows-x64.exe",安装向导会引导你完成安装过程。通常,你需要选择安装路径,...

    jdk-jdk1.6.0.24-windows-i586.exe

    标题中的"jdk-jdk1.6.0.24-windows-i586.exe"是一个Java Development Kit(JDK)的安装程序,适用于Windows操作系统且为32位版本。JDK是Oracle公司提供的一个用于开发和运行Java应用程序的软件包。这个特定的版本,...

    logback-cfca-jdk1.6-3.1.0.0.jar

    logback-cfca-jdk1.6-3.1.0.0.jar

    jdk-1.6-linux-64-2

    三部分: jdk-1.6-linux-64-1 jdk-1.6-linux-64-2 jdk-1.6-linux-64-3

    jdk-1.6-windows-32-3

    三部分: jdk-1.6-windows-32-1 jdk-1.6-windows-32-2 jdk-1.6-windows-32-3

    jdk-1.6-linux-64-1

    三部分: jdk-1.6-linux-64-1 jdk-1.6-linux-64-2 jdk-1.6-linux-64-3

    JDK1.6安装及与JDK-1.5版本共存

    ### JDK1.6安装及与JDK-1.5版本共存 #### 一、前言 随着软件开发环境的变化和技术的进步,不同的项目可能需要不同的Java版本来支持其运行。例如,在某些特定环境下,可能既需要使用JDK1.5(Java Development Kit ...

    苹果电脑安装jdk1.6 mac for jdk1.6 jdk6 安装版

    mac for jdk1.6 jdk6 安装版 里面有两个jdk1.6的安装包,都可以用 如果电脑上安装有1.7,1.8等高版本jdk就不要再下安装包了,安装包安装会报错 命令是这个:brew install java6或 brew install homebrew/cask-...

    zxing jar包,支持jdk1.6,包括源码

    - 这可能是ZXing库的完整源码包,专门针对JDK1.6编译,包含了所有必要的源文件和资源,供开发者进行更深度的定制和集成。 总之,ZXing库是一个强大的条形码和二维码工具,这个特别适配JDK1.6的版本为那些仍在使用...

    jdk-6u45-linux-x64.zip_jdk-1.6u45_jdk-6u45_jdk-6u45-linux-x64_jd

    这个压缩包文件"jdk-6u45-linux-x64.zip"包含的是JDK 1.6.0_45(也被称为6u45或1.6u45)的64位Linux版本。JDK 1.6是Java平台标准版的一个重要版本,它提供了许多功能和性能改进,是许多企业级应用的基础。 JDK 1.6u...

    jdk-1.6-linux-32-2

    jdk-1.6-linux-32-1 jdk-1.6-linux-32-2 jdk-1.6-linux-32-3

    JDK-1.6-Windows-32位 官方

    压缩包中的文件`jdk-6u45-windows-i586.exe`是JDK 1.6更新45的Windows 32位安装程序。安装步骤通常包括: 1. 下载并运行安装程序。 2. 遵循安装向导的提示,选择安装路径和组件。 3. 设置环境变量,包括`JAVA_HOME`...

    jdk1.6官方版 jdk-6u45-windows-x64 下载

    java环境搭建 jdk6(包含jre)64位 jdk-6u45-windows-x64

    jdk1.6 Java编程工具jdk-6u10-windows-i586-p.exe

    Java编程开发工具包,最新版本,很好用,经典

Global site tag (gtag.js) - Google Analytics