摘要:作者毕来生微信锁状态转换分类以后帮助我们提供了线程同步机制,通过显示定义同步锁来实现对象之间的同步。等待重新尝试因为在中是用关键字声明的,故可以在线程间可见再次判断一下能否持有锁可能线程同步代码执行得比较快,已经释放了锁,不可以就返回。
作者 : 毕来生锁状态转换 Lock分类
微信: 878799579
Jdk1.5以后帮助我们提供了线程同步机制,通过显示定义同步锁来实现对象之间的同步。还是Doug Lea这个家伙写的。相信读过源码的人在很多地方都可以看到这个家伙。
Lock可以显示的进行加锁,解锁。但是每次只能有一个线程对Lock对象加锁
Lock实现结构如下图所示:
按照使用的常用度,分别标注了(1),(2),(3)。接下来我们就主要学习一下ReentrantLock的使用
可重入锁 ReentrantLock实现的前提就是AbstractQueuedSynchronizer,简称AQS.。核心方法内部实现均在AQS中,后续我们在详细解读AQS相关知识点以及使用场景。我们先来看一段伪代码用以表述可重入锁的使用情况。接下来我们来详细分析获取锁以及释放锁内部实现到底做了什么事情。
package org.bilaisheng.juc; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author: bilaisheng * @Wechat: 878799579 * @Date: 2019/1/3 22:55 * @Todo: 伪代码仅演示使用 * @Version : JDK11 , IDEA2018 */ public class ReentrantLockTest { public static void main(String[] args) { Lock lock = new ReentrantLock(); // 获取锁 lock.lock(); // access the resource protected by this lock // do something // 释放锁 lock.unlock(); } }Sync对象剖析
/** Synchronizer providing all implementation mechanics */ private final Sync sync; /** * Base of synchronization control for this lock. Subclassed * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. */ abstract static class Sync extends AbstractQueuedSynchronizer { // xxxx }
他会根据传入构造方法的布尔类型参数实例化出Sync的实现类FairSync和NoFairSync。
FairSync: 公平的Sync
NoFairSync : 不公平的Sync
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }ReentrantLock.lock()实现原理
我们用的比较多的ReentrantLock是非公平锁,我们来用一张图来分析一下看看它是如何实现的。
上图就做了两件事情:
1、设置AbstractQueuedSynchronizer的state为1
2、设置AbstractOwnableSynchronizer的thread为当前线程
线程A正在执行中,status = 1。
线程B尝试利用CAS去判断state是不是0,是0就设置为1,当然这一步操作肯定是失败的,因为线程A已经将state设置成了1,所以此时肯定是失败的。
失败了之后进入FIFO等待队列。等待重新尝试
/** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ @ReservedStackAccess final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
因为在AbstractQueuedSynchronizer中state是用volatile关键字声明的,故可以在线程间可见
/** * The synchronization state. */ private volatile int state;
再次判断一下能否持有锁(可能线程A同步代码执行得比较快,已经释放了锁),不可以就返回false。
根据上方代码可以看出同一个锁最多能重入Integer.MAX_VALUE次,也就是2147483647。
ReentrantLock.unLock()实现原理此处较为简单。附上调用关系链路
// 步骤一 public void unlock() { sync.release(1); } // 步骤二 : AbstractQueuedSynchronizer public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } //步骤二 : ReentrantLock @ReservedStackAccess protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
当一条线程对同一个ReentrantLock全部解锁之后,AQS的state就是0了,AbstractOwnableSynchronizer的exclusiveOwnerThread将被设置为null,这样就表示没有线程占有锁,方法返回true。
喜欢就关注我吧文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/75675.html
摘要:如何在线程池中提交线程内存模型相关问题什么是的内存模型,中各个线程是怎么彼此看到对方的变量的请谈谈有什么特点,为什么它能保证变量对所有线程的可见性既然能够保证线程间的变量可见性,是不是就意味着基于变量的运算就是并发安全的请对比下对比的异同。 并发编程高级面试面试题 showImg(https://upload-images.jianshu.io/upload_images/133416...
摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...
摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...
摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...
阅读 1279·2021-10-27 14:14
阅读 3554·2021-09-29 09:34
阅读 2453·2019-08-30 15:44
阅读 1688·2019-08-29 17:13
阅读 2537·2019-08-29 13:07
阅读 847·2019-08-26 18:26
阅读 3329·2019-08-26 13:44
阅读 3197·2019-08-26 13:37