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.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-...
2部分: jdk-1.6-windows-64-01 jdk-1.6-windows-64-02
1.okhttp3.8源码使用jdk1.6重新编译,已集成了okio,在javaweb项目中使用,未在安卓项目中使用 2.okhttp3.8源码使用jdk1.6重新编译_okhttp3.8.0-jdk1.6.jar
下载的压缩包文件"jdk-6u45-windows-x64(1.6 64).exe"是Windows 64位系统的安装程序。安装过程中,用户需要选择安装路径,并设置环境变量,包括`JAVA_HOME`指向JDK的安装目录,`PATH`添加JDK的bin目录,确保系统可以...
2. **语法不兼容**:JJWT可能使用了Java 7或8的新语法,如Lambda表达式或方法引用,这些在JDK 1.6中不可用。 - **解决方案**:查找并替换使用了新语法的代码,或者使用不依赖这些特性的旧版JJWT。 3. **运行时...
三部分: jdk-1.6-linux-64-1 jdk-1.6-linux-64-2 jdk-1.6-linux-64-3
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"是一个Java Development Kit(JDK)的安装程序,适用于Windows操作系统且为32位版本。JDK是Oracle公司提供的一个用于开发和运行Java应用程序的软件包。这个特定的版本,...
logback-cfca-jdk1.6-3.1.0.0.jar
三部分: jdk-1.6-linux-64-1 jdk-1.6-linux-64-2 jdk-1.6-linux-64-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-2 jdk-1.6-linux-64-3
### JDK1.6安装及与JDK-1.5版本共存 #### 一、前言 随着软件开发环境的变化和技术的进步,不同的项目可能需要不同的Java版本来支持其运行。例如,在某些特定环境下,可能既需要使用JDK1.5(Java Development Kit ...
mac for jdk1.6 jdk6 安装版 里面有两个jdk1.6的安装包,都可以用 如果电脑上安装有1.7,1.8等高版本jdk就不要再下安装包了,安装包安装会报错 命令是这个:brew install java6或 brew install homebrew/cask-...
- 这可能是ZXing库的完整源码包,专门针对JDK1.6编译,包含了所有必要的源文件和资源,供开发者进行更深度的定制和集成。 总之,ZXing库是一个强大的条形码和二维码工具,这个特别适配JDK1.6的版本为那些仍在使用...
这个压缩包文件"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-1 jdk-1.6-linux-32-2 jdk-1.6-linux-32-3
压缩包中的文件`jdk-6u45-windows-i586.exe`是JDK 1.6更新45的Windows 32位安装程序。安装步骤通常包括: 1. 下载并运行安装程序。 2. 遵循安装向导的提示,选择安装路径和组件。 3. 设置环境变量,包括`JAVA_HOME`...
java环境搭建 jdk6(包含jre)64位 jdk-6u45-windows-x64
Java编程开发工具包,最新版本,很好用,经典