ConcurrentSkipListMap 源码全解 1、将数据插入数据节点链表,插入过程中如果发现节点被删除将帮助从链表中删除节点,如果发现该 key 已存在,根据 onlyIfAbsent 判断是否更新 value 值2、通过随机数控制是否增加索引节点和索引层级,每次最多增加一层
ConcurrentHashMap 源码全解二 **1、每个节点或者是黑色,或者是红色。** **2、根节点是黑色。** **3、每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]** **4、如果一个节点是红色的,则它的子节点必须是黑色的。** **5、从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点**
JUC 之队列 SynchronousQueue 详解 基于单链表实现的 FIFO 队列,队列中阻塞的节点要么全是 put 线程,要么全是 take 线程,一个阻塞等待另一个线程过来与之进行匹配,否则将一直阻塞在队列中直到被匹配完成退出或阻塞超时退出或被中断退出。在阻塞等待被匹配的过程中,如果你的前一个节点是头结点将会进行自旋优化,尽量避免进入 OS 阻塞。我们还发现作者为了标识节点已被取消,采用了将 节点的 item 设置为 节点 自身,这样其它线程在与之进行匹配 CAS 操作将会失败。通过将 节点的 next 赋值为节点本身,用来标识节点从队列中移除了。
@RefreshScope 注解引起的kafka无法消费问题排查 通过上述源码我们可以看到 CanalListenerAnnotationBeanPostProcessor 实现了 BeanPostProcessor(简称 BPP) 和 SmartInitializingSingleton 这两个接口,了解 spring 的同学应该知道 spring Bean 在完成实例化后会回调 BeanPostProcessor 接口中的方法(每个对象实例化时都会回调),但是回调也是有条件限制的,后面的 spring 源码中我们会看到;
JUC 之 队列 Exchanger 详解 在一个同步点上,线程可以配对和交换成对中的元素。每个线程在进入exchange方法时携带自身数据,与另一线程进行匹配,配对成功时两个线程相互交换数据并返回对方的数据。交换器可以看作是双向形式的同步队列。
JUC 之队列 LinkedBlockingQueue 详解 take 方法中 为什么使用 while 循环判断 count 是否等于 0?在多线程并发的情况下,当生产者向队列中插入了一条数据,由于 count 使用的是 AtomicInteger 的原子类,而 Condition 的唤醒操作是将等待的线程节点先移动到锁竞争的竞争队列中,然后再去抢锁等待OS唤醒调度执行
JUC 之队列 ArrayBlockingQueue 详解 take 方法中 为什么使用 while 循环判断 count 是否等于 0?在多线程并发的情况下,当生产者向队列中插入了一条数据,由于 count 使用的是 AtomicInteger 的原子类,而 Condition 的唤醒操作是将等待的线程节点先移动到锁竞争的竞争队列中,然后再去抢锁等待OS唤醒调度执行,但是在此唤醒状态过程中如果有其它线程先拿到锁把数据取走了,然后又将 count 值减为了 0,如果使用 if 条件将不会从新检测队列中的值,这时就有问题了。
JUC 之 队列基础篇讲解 Queue 接口继承自 Collection 接口,说明队列也是一个集合容器,用来存储数据的。通常队列的实现方式为FIFO(先进先出)或 LIFO(后进先出),总是从一头插入一头取数据。下面我们来看看 Queue 额外提供了什么功能。
JUC 之 CyclicBarrier 源码分析 通过上述源码可以看到,只有所有线程都到达屏障点后才属于正常情况,这时会调用 nextGeneration 方法唤醒所有等待线程、复位 count、生成新的 generation。而其他线程可能会因为被中断或超时都会造成本轮次操作的失败,即 generation.broken 被设置为了 true,其它线程检测到该值被设置纷纷抛出 BrokenBarrierException 异常而退出等待
JUC 之 CountDownLatch 源码分析 以上就是 CountDownLatch 的实现原理。就是利用 AQS 共享锁机制的同步器 Sync 来实现的。 此处读者需要注意的是 CountDownLatch 一旦创建只可使用一次,不能重复使用
JUC 之 Semaphore 信号量 利用 AQS 的共享锁机制,初始设置一个固定 state 值(初始容量),当有线程需要获取访问权时,检测 state 是否有可用资源,state > 0 代表有资源可用,获取到访问凭证后将 state 减 1;只要 state > 0 其他线程就可以获取访问凭证,直到 state = 0。利用该特性就可以完成对接口的限流操作,控制并发请求量。
JUC 之 ReentrantReadWriteLock 读写锁 通过上述源码的学习,我们知道了读写锁的实现流程。AQS 提供 state 单变量和 队列的功能,ReentrantReadWriteLock 通过操作这两个信息完成自己的功能。通过将一个整型变量 state 切割为 高低 16 位,分别用于保存读锁和写锁的信息,高 16 位表示读锁,低 16 位表示写锁。
JUC 之 ReentrantLock 源码解析 前面我们学习了 AQS 的源码,了解了 AQS 的实现原理,为我们后面即将学习的 ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore 等奠定了扎实的基础。Java 中同步器的实现均离不开 AQS 的支持。那么下面我们就从 ReentrantLock 开始逐一进行讲解。
AQS 之 Condition 源码剖析 前面我们详细讲解了互斥锁与共享锁的源码实现。有一种情况,我们可不可以控制程序在满足某一条件在继续执行呢?答案是 能,怎么做呢?JDK 提供了 Condition 条件接口,我们通过实现该接口就能控制程序的执行,下面我们来看看 AQS 中 ConditionObject 的具体实现。在看它的时候,我们只需要记住一点,针对 ConditionObject 的所有操作都是线程安全的,因为只有在先获取到锁才能去操作 ConditionObject。
AQS 之 共享锁 源码剖析 上一篇我们详细讲解了互斥锁的源码实现,也即同一时刻只有一个线程获得锁,其它参与竞争的线程必须等待。有一种情况是允许多个线程同时获得锁,如读写锁(ReentrantReadWriteLock)允许所有读线程同时获取锁,写线程阻塞,也即读读共享,读写互斥,写写互斥。那么接下来我们就来看看共享锁的源码实现。
AQS 之 互斥锁 源码剖析 AQS 是 AbstractQueuedSynchronizer 类的简称,AQS 是一个用来构建锁和同步器的基础框架,想要了解 Java 的锁实现及其底层原理就必须先了解 AQS 完成了什么,提供了哪些功能。有了AQS的基础支撑我们后面再去学 Java 锁(如ReentrantLock、ReentrantReadWriteLock、Semaphore等)相关类的源码时就会觉得很轻松。那么下面我们就开始进入 AQS 的源码之旅。
JUC源码系列之ThreadPoolExecutor ** 通过位组合的方式将线程池的运行状态和工作线程数保存在一个变量 ctl 中,高三位表示运行状态,低 29 位保存工作线程数 */ private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING , 0));/** COUNT_BITS 29位 */ private static final int COUNT_BITS = Integer . SIZE - 3;
JUC源码系列之LinkedBlockingQueue 基于单向链表实现的有界阻塞队列,遵循先进先出(FIFO)原则。可用于实现一个生产者消费者模型,由于内部使用了 takeLock 和 putLock 两把锁,还有notEmpty 和 notFull 两个条件变量,因此它可以做到读与写并行操作。使用 AtomicInteger 记录队列中元素的个数。/** 队列的容量,默认为 int 的最大值 */ private final int capacity;
JUC源码系列之SynchronousQueue ** 表示当前节点是消费者线程 */ static final int REQUEST = 0;/** 表示当前节点是生产者线程 */ static final int DATA = 1;/** 表示当前节点是匹配节点线程 */ static final int FULFILLING = 2;/** 栈的头节点 */ volatile SNode head;SNode节点变量介绍// 指向下一个节点的指针 volatile SNode match;