
并发
文章平均质量分 68
皮皮皮的代码
一点点来
展开
-
并发-AbstractQueuedSynchronizer
1. 介绍1.1 简介队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。队列同步器相当于synchronized的高级特性,带来了更好的灵活性。1.2 原理ConcurrentHashMap加锁是锁住链表或者红黑树的首节点来提高并发性能,而不是锁住所有节点。队列同步器差不多类似,保证同步器内首尾节点相关操作的并发安全,例如使用CAS添加尾节点。.原创 2021-06-09 15:21:51 · 103 阅读 · 0 评论 -
并发-ThreadLocal
1. 介绍1.1 作用ThreadLocal的作用主要是做数据隔离,填充的数据只属于当前线程,变量的数据对别的线程而言是相对隔离的。1.2 原理每个线程创建时会拥有一个Thread对象,该线程首次调用ThreaLocal.set()方法时,会创建ThreadLocalMap(这不同于HashMap,该Map由一个数组组成),利用线性检测(根据初始key的hashcode值确定元素在table数组中的位置,如果发现这个位置上已经有其他key值的元素被占用,则利用固定的算法寻找一定步长的下个原创 2021-06-07 17:07:48 · 143 阅读 · 0 评论 -
并发-重排序
1. 背景1.1 为什么需要重排序?简单的来说就是会了优化程序性能。2. 介绍重排序是编译器和处理器为了优化程序性能而对指令序列进行重排序。从Java源代码到最终实际执行的指令序列,会分别经历下面3种重排序:2.1 为什么重排序会提高性能现代CPU几乎都采用流水线机制加快指令的处理速度,一般来说,一条指令需要若干个CPU时钟周期处理,而通过流水线并行执行,可以在同等的时钟周期内执行若干条指令,具体做法简单的说就是把指令分为不同的执行周期,例如读取、寻址、解析、执行等步骤,并放原创 2020-11-22 15:11:19 · 371 阅读 · 1 评论 -
并发-同步屏障CyclicBarrier
1. 背景2. 介绍CyclicBarrier字面意思就是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情就是让一组线程到达一个屏障后(也可叫同步点)时被阻塞,直到最后一个线程到达线程时,屏障才会开门,所有被屏障拦截的线程才会继续进行。3. 源码3.1 可重入锁实现CyclicBarrier private int dowait(boolean timed, long nanos) throws InterruptedException, Brok.原创 2020-12-28 22:09:26 · 132 阅读 · 0 评论 -
基础-ConcurrentHashMap
Hash冲突 如果我们单纯的根据hashCode取余来获取对应的分组,hash碰撞的概率会大大增加。主要是因为如果使用hashCode取余,那么相当于参与运算的只有hashCode的低位,高位是没有起到任何作用的,所以我们的思路就是让hashCode取值出的高位也参与运算,进一步降低hash碰撞的概率,使得数据分布更平均,我们把这样的操作称为扰动,在JDK 1.8中的hash()函数如下:static final int hash(Object key) { int h; //..原创 2020-06-04 22:28:23 · 330 阅读 · 0 评论 -
并发-线程间通信
1. 背景2. 介绍2.1https://developer.51cto.com/art/202003/613435.htm?pc3. 源码4. 实战5. FAQ6. 参考资料原创 2020-12-13 15:13:02 · 150 阅读 · 0 评论 -
并发-Final
1. 背景2. 介绍2.1 final修饰类、方法、变量的作用修饰类:不可被继承; 修饰方法:不能被覆盖(重写); 修饰变量:一旦初始化,如果是基础类型,则不能被修改;如果是引用类型,则不能指向其它引用对象;2.2 final重排序规则在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序; 初次读一个包含final域的对象引用,与随后初次读这个final域,这两个操作之间不能重排序;2.2.1 写final域的重排序规则原创 2020-11-26 14:44:00 · 258 阅读 · 0 评论 -
并发-MESI缓存一致性协议
1. 背景1.1 为什么需要MESI缓存一致性协议CPU与主存的交互速度差异导致需要多级缓存(L1、L2、L3),缓存的存在会带来的问题就是一致性问题。很早之前采用的锁总线,也就是说除读之外的操作需要锁住总线,但是锁总线的导致效率太慢,因此采用MESI缓存一致性协议。该协议主要有一些监听的操作,就像mq生产者和消费者一样。2. 介绍3. 源码4. 实战5. FAQ6. 参考资料...原创 2020-11-23 15:31:24 · 350 阅读 · 0 评论 -
并发-内存屏障
1. 背景1.1 为什么需要内存屏障?CPU与主存的交互速度差异导致需要多级缓存(L1、L2、L3),缓存的存在会带来的问题就是一致性问题。很早之前采用的锁总线,也就是说除读之外的操作需要锁住总线,但是锁总线的导致效率太慢,因此采用MESI缓存一致性协议。该协议主要有一些监听的操作,就像mq生产者和消费者一样。当我们修改操作需要刷新主内存的时候,还要等待其它CPU返回应答消息(其它CPU也有该副本数据,也就是S状态->I状态),这其中的等待时间CPU已经能执行很多指令了,因此有写缓存区的概念(原创 2020-11-18 23:42:44 · 209 阅读 · 0 评论 -
并发-压测问题记录
1. 背景2. 介绍3.原创 2020-11-18 18:24:33 · 183 阅读 · 0 评论 -
并发- ReentrantLock
1. 背景2. 介绍可重入锁ReentrantLock,支持可重入的锁。表示同一个线程可对资源重复加锁。2.1 特性支持公平锁和非公平锁,默认是非公平锁。公平锁的存在是减少“饥饿”发生的概率,等待越久的请求优先满足;3. 源码3.1 线程如何重复获取锁及最终的释放(以非公平锁为例)final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThre原创 2020-10-22 11:22:44 · 156 阅读 · 0 评论 -
并发-Synchronized
1. 锁的四种状态(1)锁的四种状态无锁状态 偏向锁状态 轻量级锁状态 重量级锁状态(2)锁升级过程① 偏向锁升级轻量级锁偏向锁是java对象头和栈帧中记录线程ID,下次线程访问时比较是否一致,一致则扔持有锁,偏向锁不会主动释放锁,如果锁被占有期间,另一线程想持有锁资源,则撤销偏向锁,升级为轻量级锁② 轻量级锁升级重量级锁线程获取轻量级锁时,复制java对象头的markword信息至该线程的栈帧中,然后使用CAS把对象头的markword内容替换线程的锁记录。如果线程2也.原创 2020-09-12 23:36:30 · 361 阅读 · 1 评论 -
并发-FutureTask
1. 名词概念FutureTask:将要发生的任务2. 应用场景当一个线程需要等待另一个线程把某个任务执行完后它才能继续执行,此时可以使用 FutureTask。 假设有多个线程执行若干任务,每个任务最多只能被执行一次。 当多个线程试图 同时执行同一个任务时,只允许一个线程执行任务,其他线程需要等待这个任务执行完后才 能继续执行。TODO:上述场景待学习完后验证3.FutureTask内部状态流图private volatile int state;private stati.原创 2020-08-19 18:16:46 · 305 阅读 · 0 评论 -
并发-CountDownLatch
1.概念CountDownLatch允许一个或多个线程等待其他线程完成操作。CountDownLatch 定义了一个计数器和一个阻塞队列, 当计数器的值递减为0之前,阻塞队列里面的线程处于挂起状态,当计数器递减到0时会唤醒阻塞队列所有线程。这里的计数器是一个标志,可以表示一个任务一个线程,也可以表示一个倒计时器,2. 应用场景CountDownLatch可以解决那些一个或者多个线程在执行之前必须依赖于某些必要的前提业务先执行的场景3.常用方法说明CountDownLatch(i.原创 2020-08-16 23:04:44 · 154 阅读 · 0 评论 -
并发-Fork/Join
1. 什么是Fork/Join框架JAVA7 提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。2. Fork/Join 运行流程图3. Fork/Join 原理设计(1)分割任务首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还 是很大,所以还需要不停地分割,直到分割出的子任务足够小。 (2)执行任务并合并结果分割的子任务分别放在双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务.原创 2020-08-11 23:59:11 · 146 阅读 · 0 评论 -
并发-阻塞队列
1. 什么是阻塞队列 阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除方法。 支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满; 支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空; 阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是 从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。...原创 2020-08-06 23:21:01 · 192 阅读 · 0 评论 -
并发-线程池
1. 什么是线程池线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。2.原创 2020-08-02 17:54:54 · 189 阅读 · 0 评论 -
并发-Lock和Synchronized区别
1. 两者所处层面不同synchronized是Java中的一个关键字,当我们调用它时会从在虚拟机指令层面加锁,关键字为monitorenter和monitorexit; Lock是Java中的一个接口,它有许多的实现类来为它提供各种功能,加锁的关键代码为大体为Lock和unLock;2、获锁方式synchronized可对实例方法、静态方法和代码块加锁,相对应的,加锁前需要获得实例对象的锁或类对象的锁或指定对象的锁。说到底就是要先获得对象的监视器(即对象的锁)然后才能够进行相关操作; Lo.原创 2020-07-30 23:17:04 · 309 阅读 · 0 评论 -
并发-AQS同步队列与等待队列
1. 什么是AQS? 队列同步器AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组 件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获 取线程的排队工作。同步器提供的3个方法(getState()、setState(int newState)和compareAndSetState(int expect,int update))来进行操 作,因为它们能够保证状态的改变是安全的。子类推荐被定义为自定义同步组件...原创 2020-07-30 20:34:26 · 1620 阅读 · 2 评论 -
并发-Volatile解读
1. Volatile特性栈私有本地内存无效,保证读取到的是系统内存。它能保存内存可见性,但是不能保证原子性。可见性:对一个Volatile变量的读,总能看到(任意线程)对这个volatile变量最后的写入; 原子性:对任意单个Volatile变量的读/写具有原子性,但类似于Volatile++这种复合操作不具有原子性;2. Volatile应用场景如何写入的值不依赖变量当前值,那么就可以使用Volatile。其不具备互斥性,适合一个线程写,其它线程读的场景。3. 工作内存与主内存之间的原创 2020-07-19 16:42:44 · 216 阅读 · 0 评论 -
并发-锁基础知识
1.为什么要用锁锁是为了解决并发操作引起的脏读、数据不一致问题2. 锁生命周期3. CPU模型L1、L2、L3分别表示一级缓存、二级缓存、三级缓存,越靠近CPU的缓存,速度越快,容量也越小。所以L1缓存很小但很快,并且紧靠着在使用它的CPU内核;L2大一些,也慢一些,并且仍然只能被一个单独的CPU核使用;L3更大、更慢,并且被单个插槽上的所有CPU核共享;最后是主存,由全部插槽上的所有CPU核共享。PS: CPU访问不同层级数据的概念...原创 2020-07-13 23:38:06 · 174 阅读 · 0 评论