并发源码
并发底层与源码
槑!
这个作者很懒,什么都没留下…
展开
-
【线程池源码系列】ScheduledThreadPoolExecutor 源码解析
ScheduledThreadPoolExecutor虽然 Timer 与 TimerTask 可以实现线程的周期和延迟调度,但是对于定期、周期执行任务的调度策略存在一些缺陷,所以一般都是推荐ScheduledThreadPoolExecutor 来实现构造方法都是利用ThreadLocalExecutor来构造的,但是所使用的阻塞队列变成了 DelayedWorkQueueDelayedWorkQueue 为 ScheduledThreadPoolExecutor 中的内部类,它其实和阻塞队原创 2020-10-17 00:04:59 · 227 阅读 · 0 评论 -
【线程池源码系列】ThreadPoolExecutor 源码解析(下)
Wokerworker 就是工作线程的 Runnable 参数对象,线程启动后会调用其 run()// 继承 AQS 主要是为了方便线程的中断处理,即不是为了防止有多个线程来争抢什么资源,// 而是因为,如果当前线程在 getTask() 获取到 task ,要执行前会 aquire 独占锁,// 外部要中断这个线程的时候,也会先获得独占锁,那么如果当前线程正在执行某个 task // 外部就会获取失败,反之同理,从而就可以起到个 正在执行任务 和 外部中断 互斥的作用(标识作用)。privat原创 2020-10-17 00:04:45 · 134 阅读 · 0 评论 -
【线程池源码系列】ThreadPoolExecutor 源码解析(上)
ThreadPoolExecutor属性/** * 高 3 位是 线程池状态 * 后 29 位是 工作线程个数 */private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));private static final int COUNT_BITS = Integer.SIZE - 3;private static final int CAPACITY = (1 << COUNT_BITS) -原创 2020-10-17 00:04:30 · 191 阅读 · 0 评论 -
【线程池源码系列】 Executor 体系与 Future 体系解析
线程池结构ExecutorExecutor 提供了一种将“任务提交”与“任务执行”分离开来的机制,它仅提供了一个 #execute(Runnable command) 方法,用来执行已经提交的 Runnable 任务。public interface Executor { void execute(Runnable command); }ExcutorServiceExcutorService 拓展了一些方法,为了让提交执行模式更加完善,比如提交任务的:submit、invoke原创 2020-10-17 00:04:16 · 263 阅读 · 0 评论 -
【阻塞队列源码系列】 LinkedTransferQueue 源码解析
LinkedTransferQueueLinkedTransferQueue是下面三者的集合体LinkedBlockingQueue(支持阻塞,即失败入队,但不再支持获取 Lock 的阻塞了,因为是基于 cas 的)SynchronousQueue(公平模式,实现了 Transfer 接口)ConcurrentLinkedQueue (支持非阻塞,因为传统的阻塞队列都是使用的 Lock,想要 offer 或者 poll 等操作必须先获得 lock,而非阻塞是 直接cas 一次,失败就直接返回,原创 2020-10-16 23:49:07 · 328 阅读 · 0 评论 -
【阻塞队列源码系列】 SynchronousQueue 源码解析
SynchronousQueue特性SynchronousQueue 没有容量。与其他 BlockingQueue 不同,SynchronousQueue 是一个不存储元素的 BlockingQueue。可以有多个 put ,但每一个put操作必须要等待一个take操作,否则该线程会一直阻塞在 put,反之亦然。因为没有容量,所以对应 peek, contains, clear, isEmpty … 等方法其实是无效的。例如 clear 是不执行任何操作的,contains 始终返回 false,原创 2020-10-16 23:48:53 · 1500 阅读 · 2 评论 -
【阻塞队列源码系列】 DelayQueue 源码解析
DelayQueue一个支持延时获取元素的无界阻塞队列,里面的元素全部都是“可延期”的元素,**列头的元素必须是最先“到期”**的元素,如果列头不出队,其他元素是无法出队的。主要用于两个方面:缓存(清掉缓存中超时的缓存数据)、任务超时处理底层实现是优先队列,在出队时调用了内部优先队列 peek 方法先查询其队首元素,如果到期了才调用优先队列的 poll 让队首出队,否则就阻塞等队首到期,也就是说优先队列中只有前一个元素到期并出队后,后面的元素才能出队。并发安全也是通过 Lock。元素元素必须原创 2020-10-16 23:48:34 · 240 阅读 · 0 评论 -
【阻塞队列源码系列】 PriorityBlockingQueue 源码解析
PriorityBlockingQueue一个支持优先级的无界阻塞队列。默认情况下元素采用自然顺序升序排序,当然我们也可以通过构造函数来指定Comparator来对元素进行排序。需要注意的是PriorityBlockingQueue不能保证同优先级元素的顺序。底层实现是数组,采用的堆的思想(最小堆),保证数组第零个元素是最小的元素,但是注意,其增加和删除元素的调整方法并非是堆排的调整方法,即不用满足最小堆的堆排所要求的左子节点小于右子节点,只用满足根元素是最小的元素。并发安全也是通过 Lock 保证,原创 2020-10-16 23:48:19 · 259 阅读 · 0 评论 -
【阻塞队列源码系列】 LinkedBlockingDeque 源码解析
LinkedBlockingDeque实现接口 BlockingDeque,而 BlockingDeque 又继承接口 BlockingQueue ,提供了一系列的以First和Last结尾的方法,如addFirst、addLast、peekFirst、peekLast,为双向操作Queue提供了可能。底层实现就是链表,然后用 Lock 加锁,维护了头节点和尾节点LinkedBlockingQueue 介绍省略属性public class LinkedBlockingDeque<E>原创 2020-10-16 23:48:03 · 201 阅读 · 0 评论 -
【阻塞队列源码系列】 ArrayBlockingQueue 源码解析
ArrayBlockingQueue一个由数组实现的有界阻塞队列,其大小在构造时由构造函数来决定,确认之后就不能再改变了支持对等待的生产者线程和使用者线程进行排序的可选公平策略,但是在默认情况下不保证线程公平的访问,在构造时可以选择公平策略(fair = true),就是说 ReentrantLock 会变成公平锁。公平性通常会降低吞吐量,但是减少了可变性和避免了“不平衡性”。底层实现就是数组,然后用 Lock 加锁,同时维护队头和队尾索引,并且是循环的属性public class Array原创 2020-10-16 23:47:50 · 116 阅读 · 0 评论 -
【并发容器源码系列】 CopyOnWriteArrayList 源码解析
CopyOnWriteArrayListCopyOnWriteList 实现的接口和 ArrayList 完全相同,所以 ArrayList 提供的 api ,CopyOnWriteArrayList 也提供其实说白了就是每次要增、删、改的时候,会创建一个新的 array,并把旧的 array 全部复制过来,操作完后再让 array 指向这个新创建的 array,所以也不存在什么扩容问题,因为每次 add 都要扩容属性/** The lock protecting all mutato原创 2020-10-15 01:18:00 · 81 阅读 · 0 评论 -
【并发容器源码系列】ConcurrentLinkedQueue 源码解析
ConcurrentLinkedQueueNodeprivate static class Node<E> { /** 节点元素域 */ volatile E item; volatile Node<E> next; Node(E item) { UNSAFE.putObject(this, itemOffset, item); } boolean casItem(E c原创 2020-10-15 01:18:24 · 187 阅读 · 0 评论 -
【并发容器源码系列】 JDK 1.7 Concurrenthashmap 源码对比
Concurrenthashmap1.8和1.7版本实现原理JDK 1.7: ReentrantLock + Segment + HashEntry 分段锁思想(简单点说就是 Map 的所有槽位并不分布在一个 table 上,而是分布在多个 table 上,每个 table 就是一个分段,并且锁的颗粒度不再是槽位,而是一个分段的 table)hash 槽只有 HashEntry 一种类型,因为不会树化所以没有树相关节点,并且因为是分段锁,锁的是一个包含部分槽位的 table,所以也不会出现扩容和读写同原创 2020-10-16 23:47:33 · 149 阅读 · 0 评论 -
【并发容器源码系列】 ConcurrentHashMap 查找相关源码解析
size为了更好地统计size,ConcurrentHashMap提供了 baseCount 、counterCells 两个辅助变量。定义@sun.misc.Contended static final class CounterCell { volatile long value; // 该CounterCell 统计的元素个数 CounterCell(long x) { value = x; } }//ConcurrentHashMap中元素个数,但返回原创 2020-10-16 23:46:51 · 220 阅读 · 0 评论 -
【并发容器源码系列】 ConcurrentHashMap 存入相关源码解析
putpublic V put(K key, V value) { return putVal(key, value, false);}final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException(); // 计算hash值:(h ^ (h >>> 16)) & HA原创 2020-10-16 23:47:13 · 93 阅读 · 0 评论 -
【并发容器源码系列】 ConcurrentHashMap 结构相关源码解析
ConcurrentHashMaphash 槽节点类型Nodestatic class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; volatile V val; //带有volatile,保证可见性 volatile Node<K,V> next; //下一个节点的指针 Node(int hash, K原创 2020-10-16 23:46:30 · 148 阅读 · 0 评论 -
【并发工具源码系列】 Exchanger 源码解析
Exchanger线程之间可以进行元素交换(了解就行了)实际就是 Exchanger 在没有线程竞争的时候,提供了一个 Node 叫 slot 当作交换的中间场地,让你这个线程和另外一个线程把值放在 Node#item 进行交换交换流程是,如果你去交换了,但是 Node 里面没有 item 可以让你交换,那你就把你的 item 用 cas 放到 Node 里面,然后把你这个线程保存在 Node 里面,你挂起就行了,等下一个来交换的话线程,把你的 item 取走,然后把它的 item 放到 Node原创 2020-10-15 01:04:11 · 231 阅读 · 0 评论 -
【并发工具源码系列】 Semaphore 源码解析
Semaphore限制可以访问某些资源(物理或逻辑的)的线程数目实际上是就是普通共享锁,内部静态类 Sync 继承了 AQS,实现了共享锁的 tryAcquireShared、tryReleaseShared。逻辑就是正常共享锁逻辑,同时还可以实现公平和非公平可以说是 ReentrantLock 的共享版,所以注意要在 finally 里面调用 semaphore.release() 释放锁Sync 抽象类abstract static class Sync extends Ab原创 2020-10-15 01:03:53 · 132 阅读 · 0 评论 -
【并发工具源码系列】 CountDownLatch 源码解析
CountDownLatch在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待实际上是就是共享锁,内部静态类 Sync 继承了 AQS,实现了共享锁的 tryAcquireShared、tryReleaseShared但是实现是反过来的在 tryAcquireShared 获取同步状态的时候, state > 0 返回 false,state == 0,返回 true,从而达到如果 count 没减到零,那么调用 await 的线程全部进 CLH 去挂起在 tryRel原创 2020-10-15 01:03:42 · 148 阅读 · 0 评论 -
【并发工具源码系列】CyclicBarrier 源码解析
CyclicBarrier它允许一组线程互相等待,直到到达某个公共屏障点,才会进行后续任务内部是使用重入锁 ReentrantLock 及其 Condition 。因为只有一个 await 操作,不像 countDownLatch 和 Semaphore 有释放操作,所以没法调用 release,那么就用 conditon 来阻塞,不用 CLH 队列属性/** * Generation 是 CyclicBarrier 内部静态类,描述了 CyclicBarrier 的更新换代。在Cyclic原创 2020-10-15 01:03:30 · 181 阅读 · 0 评论 -
【AQS 源码系列】AQS 之 Condition 源码解析
ConditionCondition 接口// ========== 阻塞 ==========// 造成当前线程在接到信号或被中断之前一直处于等待状态。void await() throws InterruptedException; // 造成当前线程在接到信号之前一直处于等待状态。【注意:该方法对中断不敏感】。void awaitUninterruptibly(); // 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。// 返回值表示剩余时间,如果在`na原创 2020-10-15 01:01:46 · 229 阅读 · 0 评论 -
【AQS 源码系列】AQS 之 ReentrantReadWriteLock 源码解析(下)
Sync 实现类NonfairSyncwriterShouldBlock@Overridefinal boolean writerShouldBlock() { // 非公平的写锁获取前不用判断是不是要等待前面的节点 return false; // writers can always barge}readerShouldBlock@Overridefinal boolean readerShouldBlock() { // 判断是否当前写锁已经被获取原创 2020-10-15 01:01:00 · 142 阅读 · 0 评论 -
【AQS 源码系列】AQS 之 ReentrantReadWriteLock 源码解析(上)
ReentrantReadWriteLock主要特性公平性:支持公平性和非公平性。重入性:支持重入。读写锁最多支持 65535 个递归写入锁和 65535 个递归读取锁。锁降级:遵循获取写锁,再获取读锁,最后释放写锁的次序,如此写锁能够降级成为读锁。读锁、写锁都是通唯一的一个 Sync 来实现的。所以 ReentrantReadWriteLock 实际上只有一个锁(都是通过 reentrantReadWriteLock.sync 获取 sync 对象作为自己的锁)。读锁、写锁只是调用原创 2020-10-15 01:00:38 · 139 阅读 · 0 评论 -
【AQS 源码系列】AQS 之 ReentrantLock 源码解析
ReentrantLockReentrantLock 还提供了公平锁和非公平锁的选择,通过构造方法接受一个可选的 fair 参数(默认非公平锁):当设置为 true 时,表示公平锁;否则为非公平锁。非公平的原因是,在 AQS 的 acquire 方法中,如果 tryAcquire 成功了那么直接获得同步状态,不用加入 CLH 队列等待,因此非公平。Sync 抽象类ReentrantLock 的内部静态类,实现 AbstractQueuedSynchronizer 抽象类。已实现方法原创 2020-10-14 23:58:14 · 1364 阅读 · 0 评论 -
【AQS 源码系列】AQS 源码解析(下)
共享式获取acquireSharedpublic final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg);}protected int tryAcquireShared(int arg) { throw new UnsupportedOperationException();}private void doAcquireShared(int原创 2020-10-14 23:58:02 · 198 阅读 · 0 评论 -
【AQS 源码系列】AQS 源码解析(上)
AQSAbstractQueuedSynchronizer ,即队列同步器。AQS 使用一个 int 类型的成员变量 state 来表示同步状态:当 state > 0 时,表示已经获取了锁;当 state = 0 时,表示释放了锁。通过内置的 FIFO 同步队列 CLH 来完成资源获取线程的排队工作。源码主要方法1、状态相关操作#getState():返回同步状态的当前值。【可重写】#isHeldExclusively():当前同步器是否在独占式模式下被线程占用,一般该方法表示原创 2020-10-14 23:57:50 · 216 阅读 · 0 评论 -
【JUC源码系列】Fork / Join 框架源码解析
Fork / Join使用ForkJoinTask:我们要使用 ForkJoin 框架,必须首先创建一个 ForkJoin 任务。它提供在任务中执行 fork() 和 join() 操作的机制,通常情况下我们不需要直接继承 ForkJoinTask 类,而只需要继承它的子类,Fork/Join 框架提供了以下两个子类:RecursiveAction:用于没有返回结果的任务。RecursiveTask :用于有返回结果的任务。ForkJoinPool :ForkJoinTask 需要通过 F原创 2020-10-17 00:05:11 · 1373 阅读 · 2 评论 -
【JUC源码系列】ThreadLocal 源码解析
ThreadLocal每个 Thread 都有一个自己的 ThreadLocalMap,其 Key 为 ThreadLocal 对象(在每个线程的 ThreadLocalMap 中只起到一个索引的作用),Value 为 ThreadLocal 的类型参数对象在自己线程的副本比如 ThreadLocal<Integer> i,那么 key 就是 i 作为索引,value 就是自己线程的副本 IntegerThreadLocalMap 解决冲突使用的是 线性探测法,不是链地址法原创 2020-10-14 23:57:06 · 128 阅读 · 0 评论 -
【JUC源码系列】CAS 与原子类源码解析
CASUnSafeAPI /** * 举例: * var 1: 被 cas 对象 * var 2: 要被 cas 的属性,在 var 1 的字段偏移,该入参是通过 Unsafe#objectFieldOffset 获得 * var 3: 预期值,该入参通过 Unsafe#get*Volatile 获得 * var 5: 新值 */ public final native boolean compareAndSwapObject(Object var1, long v原创 2020-10-14 23:57:33 · 240 阅读 · 0 评论 -
【并发底层系列】Sychnorized 底层实现(下)
锁优化自旋锁(轻量锁手段)由来线程的阻塞和唤醒,需要 CPU 从用户态转为核心态。频繁的阻塞和唤醒对 CPU 来说是一件负担很重的工作,势必会给系统的并发性能带来很大的压力。同时,我们发现在许多应用上面,对象锁的锁状态只会持续很短一段时间。为了这一段很短的时间,频繁地阻塞和唤醒线程是非常不值得的。所以引入自旋锁。定义所谓自旋锁,就是让该线程等待一段时间,不会被立即挂起,看持有锁的线程是否会很快释放锁。怎么等待呢?执行一段无意义的循环即可(自旋)。不能替代阻塞对处理器数原创 2020-10-14 23:56:41 · 545 阅读 · 0 评论 -
【并发底层系列】Sychnorized 底层实现(上)
Sychnorized对象头32位虚拟机对象头大小= Mark Word(4B)+ kclass(4B) = 8B64位虚拟机对象头大小= Mark Word(8B)+ kclass(4B) = 12B注:在 32 位虚拟机中,1 个机器码等于 4 字节,也就是 32 bits)对象头主要包括两部分数据:Mark Word(标记字段)、Klass Pointer(类型指针)。Mark Word(1 个机器码) 用于存储对象自身的运行时数据,它是实现重量级锁、轻量级锁和偏向锁原创 2020-10-14 23:56:25 · 952 阅读 · 1 评论 -
【并发底层系列】JMM(下): volatile 底层实现
volatileJSR133 中 volatile 内存语义可以保证变量的可见性且为了配合 happens-before 的 volatile 规则 和 传递规则 所以还采用了内存屏障,防止了一些重排序,提供了一定的有序性比如 操作 A B C,A 和 B 在一个线程、C 是另外一个线程。已知关系:A happens-before B(程序次序规则)、B happns-before C (volatile 规则)那么 A happends-before C(传递规则),因此 A 对 C原创 2020-10-14 23:56:10 · 147 阅读 · 1 评论 -
【并发底层系列】JMM(上)内存模型与 happens-before
JMM内存模型Java 内存模式是一种虚拟机规范,用于屏蔽掉各种硬件和操作系统的内存访问差异,因为 JVM 会针对操作系统不同对 JMM 有不同实现,所以让Java程序在各种平台下都能达到一致的并发效果。JMM 规范了 Java 虚拟机与计算机内存是如何协同工作的,主要规范了 可见性、顺序性、原子性硬件内存结构结构:多CPU:一个现代计算机通常由两个或者多个CPU,其中一些CPU还有多核,所以可以同时运行多个线程。CPU寄存器:每个CPU都包含一系列的寄存器,它们是CPU原创 2020-10-14 23:55:50 · 195 阅读 · 0 评论 -
【并发底层系列】基础知识
基础线程状态New:这个状态呢,就是线程对象创建之后、启动之前,就是这个状态。用代码来说呢,就是Thread t = new Thread();t.getState(); // NewRunnable: 当调用start方法后呢,线程就会进入Runnable状态,表示,我这个线程可以被执行了,如果调度器给这个线程分配了CPU时间,那么这个线程就可以被执行,这里一定要正确区分一下Runnable不是说正在执行,而是可以被执行,这两个还是有区别的。Thread t = new Thread()原创 2020-10-14 23:55:32 · 227 阅读 · 0 评论