
JUC并发编程
文章平均质量分 92
埃泽漫笔
OceanBase开源项目ODC(OceanBase Developer Center)的核心贡献者,Github地址:https://github.com/oceanbase/odc,希望大家能赏脸支持下我们OceanBase公司的开源项目,点亮一颗小星星就行。
Maven中央仓库OceanBase开源组件 https://central.sonatype.com/artifact/com.oceanbase/db-browser 和 https://central.sonatype.com/artifact/com.oceanbase/ob-sql-parser 的核心贡献者。
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
异步编程源码解析
FutureTask是一个可以取消异步任务的类。FutureTask对Future做的一个基本实现。可以调用方法区开始和取消一个任务。一般是配合Callable去使用。异步任务启动之后,可以获取一个绑定当前异步任务的FutureTask。可以基于FutureTask的方法去取消任务,查看任务是否结果,以及获取任务的返回结果。FutureTask内部的整体结构中,实现了RunnableFuture的接口,这个接口又继承了Runnable, Future这个两个接口。原创 2025-05-24 23:30:59 · 648 阅读 · 0 评论 -
JUC并发工具源码
CountDownLatch就是JUC包下的一个工具,整个工具最核心的功能就是计数器。如果有三个业务需要并行处理,并且需要知道三个业务全部都处理完毕了。需要一个并发安全的计数器来操作。CountDownLatch就可以实现。给CountDownLatch设置一个数值。可以设置3。每个业务处理完毕之后,执行一次countDown方法,指定的3每次在执行countDown方法时,对3进行-1。主线程可以在业务处理时,执行await,主线程会阻塞等待任务处理完毕。原创 2025-05-24 23:19:53 · 984 阅读 · 0 评论 -
并发集合源码
红黑树是一种特殊的平衡二叉树,首选具备了平衡二叉树的特点:左子树和右子数的高度差不会超过1,如果超过了,平衡二叉树就会基于左旋和右旋的操作,实现自平衡。每个节点必须是红色或者黑色。根节点必须是黑色。如果当前节点是红色,子节点必须是黑色所有叶子节点都是黑色。从任意节点到每个叶子节点的路径中,黑色节点的数量是相同的。当对红黑树进行增删操作时,可能会破坏平衡或者是特性,这是红黑树就需要基于左旋、右旋、变色来保证平衡和特性。原创 2025-05-23 23:24:54 · 697 阅读 · 0 评论 -
线程池源码
首先ThreadPoolExecutor中,一共提供了7个参数,每个参数都是非常核心的属性,在线程池去执行任务时,每个参数都有决定性的作用。但是如果直接采用JDK提供的方式去构建,可以设置的核心参数最多就两个,这样就会导致对线程池的控制粒度很粗。所以在阿里规范中也推荐自己去自定义线程池。手动的去new ThreadPoolExecutor设置他的一些核心属性。自定义构建线程池,可以细粒度的控制线程池,去管理内存的属性,并且针对一些参数的设置可能更好的在后期排查问题。原创 2025-05-23 23:18:31 · 867 阅读 · 0 评论 -
阻塞队列BlockingQueue
首先PriorityBlockingQueue是一个优先级队列,他不满足先进先出的概念。会将查询的数据进行排序,排序的方式就是基于插入数据值的本身。如果是自定义对象必须要实现Comparable接口才可以添加到优先级队列排序的方式是基于二叉堆实现的。底层是采用数据结构实现的二叉堆。优先级队列PriorityBlockingQueue基于二叉堆实现的。PriorityBlockingQueue是基于数组实现的二叉堆。二叉堆是什么?二叉堆就是一个完整的二叉树。任意一个节点大于父节点或者小于父节点。原创 2025-05-22 23:42:40 · 649 阅读 · 0 评论 -
java中的锁详解
AQS就是AbstractQueuedSynchronizer抽象类,AQS其实就是JUC包下的一个基类,JUC下的很多内容都是基于AQS实现了部分功能,比如ReentrantLock,ThreadPoolExecutor,阻塞队列,CountDownLatch,Semaphore,CyclicBarrier等等都是基于AQS实现。首先AQS中提供了一个由volatile修饰,并且采用CAS方式修改的int类型的state变量。原创 2025-05-22 23:34:36 · 1615 阅读 · 0 评论 -
并发编程的三大特性
不同的硬件和不同的操作系统在内存上的操作有一定差异的。Java为了解决相同代码在不同操作系统上出现的各种问题,用JMM屏蔽掉各种硬件和操作系统带来的差异。让Java的并发编程可以做到跨平台。JMM规定所有变量都会存储在主内存中,在操作的时候,需要从主内存中复制一份到线程内存(CPU内存),在线程内部做计算。然后再写回主内存中(不一定!原子性的定义:原子性指一个操作是不可分割的,不可中断的,一个线程在执行时,另一个线程不会影响到他。i < 100;i++) {原创 2025-05-21 22:52:56 · 1399 阅读 · 0 评论 -
线程的基础概念
如果在main线程中调用了t1.join(2000),那么main线程会进入到等待状态,需要等待t1执行2s后,在恢复到就绪状态等待CPU调度。CPU在极短的时间内,反复切换执行不同的线程,看似好像是并行,但是只是CPU高速的切换。如果在main线程中调用了t1.join(),那么main线程会进入到等待状态,需要等待t1线程全部执行完毕,在恢复到就绪状态等待CPU调度。不如要处理一个网络等待的操作,开启一个线程去处理需要网络等待的任务,让当前业务线程可以继续往下执行逻辑,效率是可以得到大幅度提升的。原创 2025-05-21 22:50:33 · 754 阅读 · 0 评论 -
父子线程之间如何共享传递数据
通过ThreadLocal可以实现线程范围内的变量隔离,但不直接用于父子线程数据共享。Java提供了一些线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList等,可以安全并发地访问和修改,适用于需要较多线程共享数据的场景。在复杂的多线程环境下,使用Java的阻塞队列(如BlockingQueue)可以在父子线程之间传递数据,并控制线程的执行顺序。通过这些方式,父子线程可以有效地共享和传递数据,根据应用场景选择最适合的方案,以确保数据一致性和并发安全。原创 2025-02-05 23:46:20 · 493 阅读 · 0 评论 -
java并发-基础概念汇总
上下文切换是现代操作系统的基本功能,因其每次需要保存信息恢复信息,这将会占用 CPU,内存等系统资源进行处理,也就意味着效率会有一定损耗,如果频繁切换就会造成整体效率低下。这其中前三种都会发生线程切换,线程切换意味着需要保存当前线程的上下文,留待线程下次占用 CPU 的时候恢复现场。线程在执行过程中会有自己的运行条件和状态(也称上下文),比如上文所说到过的程序计数器,栈信息等。一个程序运行多个线程是没有问题,多个线程读共享资源也没有问题,在多个线程对共享资源读写操作时发生指令交错,就会出现问题。原创 2024-10-27 23:36:49 · 845 阅读 · 0 评论 -
JUC集合:ArrayBlockingQueue
Java 阻塞队列的历史可以追溯到 JDK1.5 版本,当时 Java 平台增加了,即我们常说的 JUC 包,其中包含了各种并发流程控制工具、并发容器、原子类等。这其中自然也包含了我们这篇文章所讨论的阻塞队列。为了解决高并发场景下多线程之间数据共享的问题,JDK1.5 版本中出现了和,它们是带有生产者-消费者模式实现的并发容器。其中,是有界队列,即添加的元素达到上限之后,再次添加就会被阻塞或者抛出异常。而则由链表构成的队列,正是因为链表的特性,所以在添加元素上并不会向那样有着较多的约束,所以。原创 2024-11-16 00:33:53 · 613 阅读 · 0 评论 -
java并发-线程状态流转及基本使用
如果只想中断 Executor 中的一个线程,可以通过使用 submit() 方法来提交一个线程,它会返回一个 Future原创 2024-10-27 23:37:34 · 783 阅读 · 0 评论 -
Java并发-JMM以及并发三要素
在Java语言里面,Happens-before的语义本质上是一种可见性A happens-before B ,意味着A发生过的事情对B而言是可见的,无论A事件和B事件是否发生在同一线程里JVM的设计分为两部分:一部分是面向我们程序员提供的,也就是happens-before规则,它通俗易懂的向我们程序员阐述了一个强内存模型,我们只要理解happens-before规则,就可以编写并发安全的程序了。原创 2024-10-27 23:38:35 · 1045 阅读 · 0 评论 -
java并发-java中的锁
Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率。本文旨在对锁相关源码(本文中的源码来自JDK 8和Netty 3.10.6)、使用场景进行举例,为读者介绍主流锁的知识点,以及不同的锁的适用场景。Java中往往是按照是否含有某一特性来定义锁,我们通过特性将锁进行分组归类,再使用对比的方式进行介绍,帮助大家更快捷的理解相关知识。原创 2024-10-27 23:44:13 · 826 阅读 · 0 评论 -
Java对象结构
在HotSpot虚拟机里,对象在堆内存的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data) 和对齐填充(Padding)。原创 2024-10-27 23:43:21 · 399 阅读 · 0 评论 -
ThreadLocal
ThreadLocal中ThreadLocalMap的数据结构和关系ThreadLocal的key是弱引用,这是为什么?ThreadLocal内存泄漏问题你知道吗?ThreadLocal中最后为什么要加remove方法?问题描述:5个销售买房子,集团只关心销售总量的准确统计数,按照总销售额统计,方便集团公司给部分发送奖金--------群雄逐鹿起纷争------为了数据安全只能加锁/*** 需求:5个销售卖房子,集团只关心销售总量的精确统计数*/i <= 5;i++) {原创 2024-10-27 23:42:45 · 1104 阅读 · 0 评论 -
CAS与自旋锁
再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。CAS是实现自旋锁的基础,CAS利用CPU指令保证了操作的原子性,以达到锁的效果,至于自旋锁---字面意思自己旋转。是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,当线程发现锁被占用时,会不断循环判断锁的状态,直到获取。题目:实现一个自旋锁,借鉴CAS思想。原创 2024-10-27 23:41:25 · 953 阅读 · 0 评论 -
atomic包:原子类
public final int get() //获取当前的值public final int getAndSet(int newValue)//获取当前的值,并设置新的值public final int getAndIncrement()//获取当前的值,并自增public final int getAndDecrement() //获取当前的值,并自减public final int getAndAdd(int delta) //获取当前的值,并加上预期的值。原创 2024-10-27 23:42:06 · 1000 阅读 · 0 评论 -
关键字:volatile
volatile关键字保证可见性:对一个被volatile关键字修饰的变量1写操作的话,这个变量的最新值会立即刷新回到主内存中2读操作的话,总是能够读取到这个变量的最新值,也就是这个变量最后被修改的值3当某个线程收到通知,去读取volatile修饰的变量的值的时候,线程私有工作内存的数据失效,需要重新回到主内存中去读取最新的数据。volatile写之前的操作,都禁止重排序到volatile之后volatile读之后的操作,都禁止重排序到volatile之前。原创 2024-10-27 23:39:18 · 1030 阅读 · 0 评论 -
关键字:synchronized
出现场景:一个对象有多个线程要加锁,但加锁的时间是错开的(没有竞争),可以使用轻量级锁来优化,轻量级锁对使用者是透明的(不可见),即语法仍然是synchronized。线程不安全:因为锁住的不是同一个对象,线程 1 调用 a 方法锁住的类对象,线程 2 调用 b 方法锁住的 n2 对象,不是同一个对象。在尝试加轻量级锁的过程中,CAS 操作无法成功,可能是其它线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为。锁消除是指对于被检测出不可能存在竞争的共享数据的锁进行消除,这是 JVM。原创 2024-10-27 02:01:27 · 791 阅读 · 0 评论 -
关键字:final
final可以修饰变量,方法和类,用于表示所修饰的内容一旦赋值之后就不会再被改变,比如String类就是一个final类型的类。即使能够知道final具体的使用方法,我想对于final在多线程中存在的重排序问题也很容易忽略,希望能够一起做下探讨。原创 2024-11-08 01:17:51 · 1116 阅读 · 0 评论 -
locks包:Condition
任何一个java对象都天然继承于Object类,在线程间实现通信的往往会应用到Object的几个方法,比如wait(),wait(long timeout),wait(long timeout, int nanos)与notify(),notifyAll()几个方法实现等待/通知机制,同样的, 在java Lock体系下依然会有同样的方法实现等待/通知机制。从整体上来看Object的wait和notify/notify是与对象监视器配合完成线程间的等待/通知机制,而Condition与Lock。原创 2024-11-16 23:44:22 · 699 阅读 · 0 评论 -
locks包:LockSupport
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,其中park()和unpack()而作用分别是。所以需要引入LockSupport。Permit(许可)原创 2024-10-28 20:52:53 · 871 阅读 · 0 评论 -
locks包:AbstractQueuedSynchronizer初步认识
和AQS有关的Semaphore进一步理解锁和同步器的关系锁,面向锁的使用者:定义了程序员和锁交互的使用层API,隐藏了实现细节,你调用即可同步器,面向锁的实现者:Java并发大神DoungLee,提出了统一规范并简化了锁的实现,将其抽象出来,屏蔽了同步状态管理、同步队列的管理和维护、阻塞线程排队和通知、唤醒机制等,是一切锁和同步组件实现的----公共基础部分AQS同步队列的基本结构。原创 2024-10-27 23:45:58 · 1072 阅读 · 0 评论 -
locks包:AQS
AbstractQueuedSynchronizer抽象类是JUC的核心,需要重点掌握。它提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步器的基础框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask等等皆是基于AQS的。当然,我们自己也能利用AQS非常轻松容易地构造出符合我们自己需求的同步器。原创 2024-11-16 00:18:45 · 1404 阅读 · 0 评论 -
locks包:ReentrantLock
说明: 跟踪lock方法的源码可知,当资源空闲时,它总是会先判断sync队列(AbstractQueuedSynchronizer中的数据结构)是否有等待时间更长的线程,如果存在,则将该线程加入到等待队列的尾部,实现了公平获取原则。其中,FairSync类的lock的方法调用如下,只给出了主要的方法。说明: 首先,t1线程的lock操作 -> t2线程的lock操作 -> t3线程的lock操作 -> t1线程的unlock操作 -> t2线程的unlock操作 -> t3线程的unlock操作。原创 2024-11-10 23:33:40 · 1067 阅读 · 0 评论 -
locks包:ReentrantReadWriteLock
锁降级指的是写锁降级成为读锁。如果当前线程拥有写锁,然后将其释放,最后再获取读锁,这种分段完成的过程不能称之为锁降级。锁降级是指把持住(当前拥有的)写锁,再获取到读锁,随后释放(先前拥有的)写锁的过程。接下来看一个锁降级的示例。if (!update) {// 必须先释放读锁// 锁降级从写锁获取到开始try {if (!update) {// 准备数据的流程(略)// 锁降级完成,写锁降级为读锁try {// 使用数据的流程(略)原创 2024-11-10 23:51:44 · 1057 阅读 · 0 评论 -
JUC集合: ConcurrentHashMap
HashTable: 使用了synchronized关键字对put等操作进行加锁;: 使用分段锁机制实现;: 则使用数组+链表+红黑树数据结构和CAS原子操作实现;原创 2024-11-14 01:06:31 · 774 阅读 · 0 评论 -
JUC集合:CopyOnWriteArrayList
在 JDK1.5 之前,如果想要使用并发安全的 List 只能选择 Vector。而 Vector 是一种老旧的集合,已经被淘汰。Vector 对于增删改查等方法基本都加了 synchronized,这种方式虽然能够保证同步,但这相当于对整个 Vector 加上了一把大锁,使得每个方法执行的时候都要去获得锁,导致性能非常低下。原创 2024-11-15 02:22:12 · 1062 阅读 · 0 评论 -
JUC集合: ConcurrentLinkedQueue
ConcurerntLinkedQueue一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部是队列中停留时间最长的元素。队列的尾部是队列中停留时间最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue是一个恰当的选择。此队列不允许使用null元素。原创 2024-11-15 02:29:41 · 1164 阅读 · 0 评论 -
JUC集合: BlockingQueue使用介绍
你可以在对其初始化的时候设定这个上限,但之后就无法对这个上限进行修改了(译者注: 因为它是基于数组实现的,也就具有数组的特性: 一旦初始化,大小就无法修改)。队列中的头元素在所有元素之中是放入时间最久的那个,而尾元素则是最短的那个。因此,双端队列是一个你可以从任意一端插入或者抽取元素的队列。如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。原创 2024-11-15 23:57:11 · 1052 阅读 · 0 评论 -
JUC集合:DelayQueue
DelayQueue是 JUC 包(为我们提供的延迟队列,用于实现延时任务比如订单下单 15 分钟未支付直接取消。它是的一种,底层是一个基于实现的一个无界队列,是线程安全的。DelayQueue中存放的元素必须实现Delayed接口,并且需要重写getDelay()方法(计算是否到期)。默认情况下,DelayQueue会按照到期时间升序编排任务。只有当元素过期时(getDelay()方法返回值小于等于 0),才能从队列中取出。原创 2024-11-16 01:39:14 · 860 阅读 · 0 评论 -
JUC线程池:ThreadPoolExecutor
和newFixedThreadPool创建的线程池不同,newCachedThreadPool在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源,当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销;然后分配给线程池十个工作,因为线程池大小为五,它将启动五个工作线程先处理五个工作,其他的工作则处于等待状态,一旦有工作完成,空闲下来工作线程就会捡取等待队列里的其他工作进行执行。当队列中有任务加入时,线程被唤醒,take方法返回任务,并执行;原创 2024-11-13 00:29:12 · 680 阅读 · 0 评论 -
JUC线程池: ScheduledThreadPoolExecutor
在很多业务场景中,我们可能需要周期性的运行某项任务来获取结果,比如周期数据统计,定时发送数据等。在并发包出现之前,Java 早在1.3就提供了 Timer 类(只需要了解,目前已渐渐被 ScheduledThreadPoolExecutor 代替)来适应这些业务场景。随着业务量的不断增大,我们可能需要多个工作线程运行任务来尽可能的增加产品性能,或者是需要更高的灵活性来控制和监控这些周期业务。这些都是 ScheduledThreadPoolExecutor 诞生的必然性。原创 2024-11-13 00:35:02 · 549 阅读 · 0 评论 -
JUC线程池:FutureTask
Future 表示了一个任务的生命周期,是一个可取消的异步运算,可以把它看作是一个异步操作的结果的占位符,它将在未来的某个时刻完成,并提供对其结果的访问。在并发包中许多异步任务类都继承自Future,其中最典型的就是 FutureTask。FutureTask 为 Future 提供了基础实现,如获取任务执行结果(get)和取消任务(cancel)等。如果任务尚未完成,获取任务执行结果时将会阻塞。一旦执行结束,任务就不能被重启或取消(除非使用runAndReset执行计算)。原创 2024-11-13 00:05:00 · 982 阅读 · 0 评论 -
JUC线程池:CompletableFuture
类架构说明接口CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段。一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发类CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合CompletableFuture的方法。原创 2024-10-28 00:10:58 · 718 阅读 · 0 评论 -
JUC线程池: Fork/Join框架
ForkJoinPool 是JDK 7加入的一个线程池类。Fork/Join框架是Java并发工具包中的一种可以将一个大任务拆分为很多小任务来异步执行的工具。Fork/Join 技术是分治算法(Divide-and-Conquer)的并行实现,它是一项可以获得良好的并行性能的简单且高效的设计技术。目的是为了帮助我们更好地利用多处理器带来的好处,使用所有可用的运算能力来提升应用的性能。原创 2024-11-14 00:52:37 · 1024 阅读 · 0 评论 -
JUC工具类: CountDownLatch(倒计时器)
从源码可知,其底层是由AQS提供支持,所以其数据结构可以参考AQS的数据结构,而AQS的数据结构核心就是两个虚拟队列: 同步队列sync queue 和条件队列condition queue,不同的条件会有不同的条件队列。CountDownLatch典型的用法是将一个程序分为n个互相独立的可解决任务,并创建值为n的CountDownLatch。当每一个任务完成时,都会在这个锁存器上调用countDown,等待问题被解决的任务调用这个锁存器的await,将他们自己拦住,直至锁存器计数结束。原创 2024-11-11 01:23:15 · 1005 阅读 · 0 评论 -
JUC工具类:CyclicBarrier(循环栅栏)
对于CountDownLatch,其他线程为游戏玩家,比如英雄联盟,主线程为控制游戏开始的线程。在所有的玩家都准备好之前,主线程是处于等待状态的,也就是游戏不能开始。当所有的玩家准备好之后,下一步的动作实施者为主线程,即开始游戏。对于CyclicBarrier,假设有一家公司要全体员工进行团建活动,活动内容为翻越三个障碍物,每一个人翻越障碍物所用的时间是不一样的。但是公司要求所有人在翻越当前障碍物之后再开始翻越下一个障碍物,也就是所有人翻越第一个障碍物之后,才开始翻越第二个,以此类推。原创 2024-11-11 01:33:09 · 681 阅读 · 0 评论 -
JUC工具类:Semaphore(信号量)
说明: 如上图所示,首先,main线程执行acquire操作,并且成功获得许可,之后t1线程执行acquire操作,成功获得许可,之后t2执行acquire操作,由于此时许可数量不够,t2线程将会阻塞,直到许可可用。之后t1线程释放许可,main线程释放许可,此时的许可数量可以满足t2线程的要求,所以,此时t2线程会成功获得许可运行,t2运行完成后释放许可。说明: 首先,生成一个信号量,信号量有10个许可,然后,main,t1,t2三个线程获取许可运行,根据结果,可能存在如下的一种时序。原创 2024-11-11 01:47:23 · 875 阅读 · 0 评论