【JUC源码解析】ReentrantReadWriteLock】的更多相关文章

简介 它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行.在多线程或者对灵活性有要求的环境下,要优于java.util.Timer. 提交的任务在执行之前支持取消,默认情况下,在延迟到来之前,不会自动从队列中删除,但可以设置,使其立刻从队列中移除. 有两种模式,固定频率(scheduleAtFixedRate)和固定延迟(scheduleWithFixedDelay),不管哪种模式,同一个任务不会被叠加执行,即便是不同的线程执行同一个任务. 继承Thr…
简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释放[存数据线程]: 同理,[取数据线程]到达队列后,若发现没有[存数据线程]在此等待,则[取数据线程]便入队等待,直到有[存数据线程]来存数据,并释放[取数据线程]. 非公平模式,由伪栈实现,TransferStack 公平模式,由伪队列实现,TransferQueue 源码解析 Transfere…
简介 ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性.对于那种大任务分割小任务的场景(分治)尤其有用. 框架图 几个角色 ForkJoinTask: 有3个实现,分别是RecursiveTask,RecursiveAction,CountedCompleter. RecursiveTask: 可以递归执行的ForkJoinTask. RecursiveAction: 无返回值的RecursiveTask.…
简介 基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首.只有过期的元素才能出队,在此之前,线程等待. 源码解析 属性 private final transient ReentrantLock lock = new ReentrantLock(); // 可重入锁 private final PriorityQueue<E> q = new PriorityQueue<E>(); // 优先级队列 private Thread leader = null; //…
简介 CyclicBarrier,一个同步器,允许多个线程相互等待,直到达到一个公共屏障点. 概述 CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后,释放所有线程之前,该命令只在屏障点运行一次. 应用 描述 有一个矩阵,每一行数据交给一个线程去处理,处理内容是,将这行数据的每一个值相加,结果存入第一个元素中,每个线程处理完成后,会在屏障点相互等待,直到最后一个线程也到达屏障点,最后将各个线程处理的数据汇总,具体是将每一行汇总的数据(存在每行的第…
简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当前排队时间最短的.新元素,从队尾插入:检索元素,从队首开始,Node的next属性保证从队首能遍历到所有的有效元素.由于此队列使用Node的next属性联接在一起,因此不允许有null元素. 队列的实现具有非阻塞,弱一致性,滞后更新等特点. 队列维护两个指针,head指针和tail指针,一开始,he…
简介 Exchanger,并发工具类,用于线程间的数据交换. 使用 两个线程,两个缓冲区,一个线程往一个缓冲区里面填数据,另一个线程从另一个缓冲区里面取数据.当填数据的线程将缓冲区填满时,或者取数据的线程将缓冲区里的数据取空时,就主动向对方发起交换缓冲区的动作,而交换的时机是,一个缓冲区满,另一个缓冲区空.代码如下,很简单,没有加注释. public class FillAndEmpty { Exchanger<DataBuffer> exchanger = new Exchanger<…
简介 ReentrantReadWriteLock, 可重入读写锁,包括公平锁和非公平锁,相比较公平锁而言,非公平锁有更好的吞吐量,但可能会出现队列里的线程无限期地推迟一个或多个读线程或写线程的情况,因为后来的线程不必入队等待就可以竞争锁. 概述 读写锁,分为读锁(共享锁)和写锁(独占锁),有两种模式,包括公平模式和非公平模式. 非公平模式 读写锁的默认模式,竞争到锁的线程是无序的,因为,后来者可能先抢到线程,这大大增加了吞吐量. 对于写锁而言,如果当前线程具备获得锁的条件,则可以直接闯入获取锁…
功能简介: ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列.队列中的元素遵循先入先出(FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素. 和普通队列有所不同,该队列支持阻塞操作.比如从空队列中取元素,会导致当前线程阻塞,直到其他线程将元素放入队列:将元素插入已经满的队列,同样会导致当前线程阻塞,直到其他线程从队列中取出元素. ArrayBlockingQueue也支持公平和非公平策略(针对队列中元素的存取线程,也可认为是元素的生产者和消费者). 源码分析: A…
功能简介: AbstractQueuedSynchronizer(以下简称AQS)是Java并发包提供的一个同步基础机制,是并发包中实现Lock和其他同步机制(如:Semaphore.CountDownLatch和FutureTask等)的基础. AQS内部包含一个FIFO的同步等待队列,简单的说,没有成功获取控制权的线程会在这个队列中等待. AQS内部管理了一个原子的int域作为内部状态信息,并提供了一些方法来访问该域,基于AQS实现的同步机制可以按自己的需要来灵活使用这个 int域,比如:R…
功能简介: LinkedBlockingQueue是一种基于单向链表实现的有界的(可选的,不指定默认int最大值)阻塞队列.队列中的元素遵循先入先出 (FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素.(在并发程序中,基于链表实现的队列和基于数组实现的队列相比,往往具有更高的吞吐 量,但性能稍差一些) 源码分析: 首先看下LinkedBlockingQueue内部的数据结构: public class LinkedBlockingQueue<E> extends AbstractQ…
功能简介: Java代码层面提供的锁机制,可做为Synchronized(jvm内置)的替代物,和Synchronized一样都是可重入的. 与Synchronized相比较而言,ReentrantLock有以下优 势:支持公平/非公平锁.支持可中断的锁.支持非阻塞的tryLock(可超时).支持锁条件.可跨代码块使用(一个地方加锁,另一个地方解锁),总之比 Synchronized更加灵活.但也有缺点,比如锁需要显示解锁.无法充分享用JVM内部性能提升带来的好处等等. 源码分析: Reentr…
转自:http://brokendreams.iteye.com/blog/2250109 功能简介: 原子量和普通变量相比,主要体现在读写的线程安全上.对原子量的是原子的(比如多线程下的共享变量i++就不是原子的),由CAS操作保证原子性.对原子量的读可以读到最新值,由volatile关键字来保证可见性. 原子量多用于数据统计(如接口调用次数).一些序列生成(多线程环境下)以及一些同步数据结构中. 源码分析: 首先,原子量的一些较底层的操作都是来自sun.misc.Unsafe类,所以原子量内…
简介 先说Future, 它用来描述一个异步计算的结果.isDone方法可以用来检查计算是否完成,get方法可以用来获取结果,直到完成前一直阻塞当前线程,cancel方法可以取消任务.而对于结果的获取,只能通过阻塞(get())或者轮询的方式[while(!isDone)]. 阻塞的方式违背了异步编程的理念,轮询的方式耗费无谓的CPU资源(CPU空转).于是,CompletableFuture应运而生. 样例 后面介绍的源码都会以下面的用例为切入点,循着调用轨迹理解源码.如果任务很耗时,记得传E…
简介 Phaser,阶段器,可作为一个可复用的同步屏障,与CyclicBarrier和CountDownLatch类似,但更强大. 全览图 如上图所示,phaser,支持phaser树(图中,简化为phaser链表模式,独子单传,后文也称phaser链)模式,分摊并发的压力.每个phaser结点的father指针指向前一个phaser结点,最前头的结点成为root结点,其father指针指向null, 每一个结点的root指针指向root结点,root结点的root指针指向它自己. 只有root…
简介 基于数据结构堆实现的线程安全的无界队列,这个堆的内存结构是数组,结合了数组和二叉树的特点. 堆 以下内容参考<编程珠玑>和<算法导论>有关堆的章节. 数据结构 堆是用来表示元素集合的一种数据结构. 性质 顺序,任何结点的值都小于(大或于)等于其子结点的值. 形状,是一个数组,却可以被看成一个近似的完全二叉树,除了底层外,该树是完全充满的,而且是从左往右填充. 如上图所示,堆使用的是从下标1开始的数组,常见的方法如下: root = 1 value(i) = x[i] left…
简介 基于跳表,支持并发,有序的哈希表. 跳表 红色路径为寻找结点F. 拿空间换时间,时间复杂度,O(nlogn). 源码分析 内部类 Node 属性 final K key; // 键 volatile Object value; // 值 volatile Node<K,V> next; // 指向下一个结点 最底层是基础层,即使结点(Node)层,保存实际数据(value),next指向下一个结点 构造方法 Node(K key, Object value, Node<K,V>…
简介 支持并发的哈希表.其中包括红黑树,扩容,分槽计数等知识点. 源码分析 常量 private static final int MAXIMUM_CAPACITY = 1 << 30; // 最大容量 private static final int DEFAULT_CAPACITY = 16; // 默认容量,2^n static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 可能的最大数组大小 private static fi…
简介 一个基于链表的阻塞队列,FIFO的顺序,head指向的元素等待时间最长,tail指向的元素等待时间最短,新元素从队列尾部添加,检索元素从队列头部开始,队列的容量,默认是Integer#MAX_VALUE. 源码分析 内部类Node static class Node<E> { E item; // 结点的值 Node<E> next; // 指向下一个结点 Node(E x) { // 构造方法 item = x; } } 属性 private final int capac…
简介 Semaphore(信号量),概念上讲,一个信号量持有一组许可(permits). 概述 线程可调用它的acquire()方法获取一个许可,不成功则阻塞:调用release()方法来归还一个许可,前提是已经拿到过一个许可.然而,并没有什么实际的许可对象,Semaphore只是记录了一个数字,并根据这个数字管控线程. 应用 描述 有一组数据items,其实是26个大写的英文字母,有52个线程从中取数据(getItem),每个线程取一个数据,有一个线程不停地往里面放数据(putItem)直至取…
简介 CountDownLatch,是一个同步器,允许一个或多个线程等待,直到一组操作在其他线程中完成. 概述 初始CountDownLatch时,会给定count,await方法会阻塞,直到count减小到0,countDown方法会是count减1,count不能被重置. 应用 例一 描述 有1个老板,雇了10工人,工人就位后,并不是立即工作,而是等到老板发出指令,才会开始工作,每个工人完成工作后,也会发出一个指令反馈完成此工作,而老板会等待所有的工人都完成工作,然后做下一步打算. 代码 p…
简介 FutureTask, 一个支持取消行为的异步任务执行器. 概述 FutureTask实现了Future,提供了start, cancel, query等功能,并且实现了Runnable接口,可以提交给线程执行. 源码分析 状态 private volatile int state; // 执行器状态 private static final int NEW = 0; // 初始值 private static final int COMPLETING = 1; // 完成进行时 priv…
简介 ThreadPoolExecutor,线程池的基石. 概述 线程池,除了用HashSet承载一组线程做任务以外,还用BlockingQueue承载一组任务.corePoolSize和maximumPoolSize,分别表示线程弛里存活的最小和最大线程数目,keepAliveTime表示不干活的线程的存活时间.当过来一个任务时,如果线程池里的线程数目小于corePoolSize,那么直接创建一个线程去处理它:如果线程数目大于等corePoolSize并且小于maximumPoolSize,那…
简介 AQS,也即AbstractQueuedSynchronizer,抽象队列同步器,提供了一个框架,可以依赖它实现阻塞锁和相关同步器.有两种类型,独占式(Exclusive)和共享式(Share). 概述 同步器,维护了一个共享状态(state)和一个同步队列(链表). 共享状态,表示共享资源的状态:初始时为0,表示未锁定,当有一个线程成功抢占此资源时,状态加1,释放资源时,状态减1:通过CAS改变state,一般需要子类实现具体的逻辑. 同步队列(链表,Node),当一个线程抢占资源失败时…
读写锁实现逻辑相对比较复杂,但是却是一个经常使用到的功能,希望将我对ReentrantReadWriteLock的源码的理解记录下来,可以对大家有帮助 前提条件 在理解ReentrantReadWriteLock时需要具备一些基本的知识 理解AQS的实现原理 之前有写过一篇<深入浅出AQS源码解析>关于AQS的文章,对AQS原理不了解的同学可以先看一下 理解ReentrantLock的实现原理 ReentrantLock的实现原理可以参考<深入浅出ReentrantLock源码解析>…
目录 非阻塞并发队列ConcurrentLinkedQueue概述 结构组成 基本不变式 head的不变式与可变式 tail的不变式与可变式 offer操作 源码解析 图解offer操作 JDK1.6 hops设计意图 poll操作 源码解析 图解poll操作 总结 参考阅读 非阻塞并发队列ConcurrentLinkedQueue概述 我们之前花了很多时间了解学习BlockingQueue阻塞队列接口下的各种实现,也大概对阻塞队列的实现机制有了一定的了解:阻塞 + 队列嘛. 而且其中绝大部分是…
问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的TreeMap? 简介 读写锁是一种特殊的锁,它把对共享资源的访问分为读访问和写访问,多个线程可以同时对共享资源进行读访问,但是同一时间只能有一个线程对共享资源进行写访问,使用读写锁可以极大地提高并发量. 特性 读写锁具有以下特性: 是否互斥 读 写 读 否 是 写 是 是 可以看到,读写锁除了读读…
ReentrantReadWriteLock 前情提要:在学习本章前,需要先了解笔者先前讲解过的ReentrantLock源码解析和Semaphore源码解析,这两章介绍了很多方法都是本章的铺垫.下面,我们进入本章正题ReentrantReadWriteLock. ReentrantReadWriteLock与ReentrantLock的使用方式有些相似,它提供了读锁(ReadLock)和写锁(WriteLock),这两种锁都实现了java.util.concurrent.locks.Lock这…
先前,笔者和大家一起了解了ReentrantReadWriteLock的写锁实现,其实写锁本身实现的逻辑很少,基本上还是复用AQS内部的等待队列思想.下面,我们来看看ReentrantReadWriteLock的读锁实现. 当调用读锁的lock()方法时,会调用到Sync的父类AQS实现的acquireShared(int arg)方法,在这个方法又会调用子类实现的tryAcquireShared(arg)方法尝试获取读锁,如果返回大于等于0,则代表获取读锁成功,返回结果小于0代表获取读锁失败.…
JUC源码学习笔记5--线程池,FutureTask,Executor框架源码解析 源码基于JDK8 参考了美团技术博客 https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html 一丶Executor框架概览 刚接触Java线程池的时候,常常被ThreadPoolExecutor,Executor,ExecutorService,Future,FutureTask搞得一头雾水,下面我们先来来理一理这些类的关系…