Java并发编程
文章平均质量分 93
主要围绕Java并发编程的技术原理与实践进行讲解。
香农派我最爱
I'm vegetable!
展开
-
刨根问底-Condition
刨根问底-ConditionCondtion的实现等待队列等待通知Condition的应用Condtion的实现Condition提供了一系列的方法来对阻塞和唤醒线程:await() :造成当前线程在接到信号或被中断之前一直处于等待状态。await(long time, TimeUnit unit) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。awaitNanos(long nanosTimeout) :造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待原创 2022-03-20 18:04:33 · 476 阅读 · 0 评论 -
刨根问底-ReentrantReadWriteLock
刨根问底-ReentrantReadWriteLock引言写锁的获取写锁的释放读锁的获取读锁的释放HoldCounter锁降级引言重入锁ReentrantLock是排他锁,排他锁在同一时刻仅有一个线程可以进行访问,但是在大多数场景下,大部分时间都是提供读服务,而写服务占有的时间较少。然而读服务不存在数据竞争问题,如果一个线程在读时禁止其他线程读势必会导致性能降低。所以就提供了读写锁。 读写锁维护着一对锁,一个读锁和一个写锁。通过分离读锁和写锁,使得并发性比一般的排他锁有了较大的提升:在同一时间可以允许多原创 2022-03-19 20:23:40 · 146 阅读 · 0 评论 -
刨根问底-ReentrantLock
刨根问底-ReentrantLock引言获取锁释放锁公平锁与非公平锁ReentrantLock与synchronized的区别引言ReentrantLock,可重入锁,是一种递归无阻塞的同步机制。它可以等同于synchronized的使用,但是ReentrantLock提供了比synchronized更强大、灵活的锁机制,可以减少死锁发生的概率。 API介绍如下:一个可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强原创 2022-03-14 23:45:03 · 137 阅读 · 0 评论 -
刨根问底-AQS源码解析
刨根问底-AQS源码解析CLH同步队列入队列出队列同步状态的获取与释放独占式同步状态获取独占式获取响应中断独占式超时获取独占式同步状态释放共享式同步状态获取共享式同步状态释放阻塞和唤醒线程LockSupportAQS使用案例CLH同步队列AQS内部维护着一个FIFO队列,该队列就是CLH同步队列。CLH同步队列是一个FIFO双向队列,AQS依赖它来完成同步状态的管理,当前线程如果获取同步状态失败时,AQS则会将当前线程已经等待状态等信息构造成一个节点(Node)并将其加入到CLH同步队列,同时会阻塞当原创 2022-03-13 19:54:57 · 998 阅读 · 0 评论 -
刨根问底-JVM类加载死锁
刨根问底-JVM类加载死锁引言类加载中的初始化类加载中的死锁引言单例模式大家都了解,其中懒汉式如下:public class Singleton { private static Singleton singleton; private Singleton(){} public static Singleton getInstance(){ if(singleton == null){ si原创 2022-03-08 09:11:37 · 538 阅读 · 0 评论 -
刨根问底-Volatile原理&Java内存模型
刨根问底-Volatile原理&Java内存模型引言内存模型相关概念操作系统语义Java内存模型volatile原理volataile的内存语义及其实现Java内存模型happens-beforeas-if-serialvolatile与happens-before引言Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。保证共享变量的可见性可以通过锁也可以通过volatile,今天我们来讲volatile。内存模型相关概念既然要原创 2022-03-05 22:30:18 · 471 阅读 · 0 评论 -
刨根问底-Synchronized实现原理
刨根问底-Synchronized实现原理引言实现原理Java对象头Monitor锁优化自旋锁适应自旋锁锁消除锁粗化轻量级锁偏向锁重量级锁引言初入Java学习殿堂时,提起并发加锁操作首先都会想到用synchronized,同时我们也知道它是一个重量级锁,相对于Lock,它会显得那么笨重,以至于我们认为它不是那么的高效而慢慢摒弃它。伴随Javs SE 1.6对synchronized进行的各种优化后,synchronized现在并没有我们想象的那么重。今天我们将讲述synchronized的实现机制、J原创 2022-02-27 01:59:18 · 250 阅读 · 0 评论 -
并发编程设计之生产者-消费者模式:用流水线思想提高效率
并发编程设计之生产者-消费者模式:用流水线思想提高效率引言生产者 - 消费者模式的优点支持批量执行以提升性能支持分阶段提交以提升性能引言Java 线程池本质上就是用生产者 - 消费者模式实现的,所以每当使用线程池的时候,其实就是在应用生产者 - 消费者模式。 Log4j2 中异步 Appender 内部也用到了生产者 - 消费者模式。Java 语言提供的线程池本身就是一种生产者 - 消费者模式的实现,但是线程池中的线程每次只能从任务队列中消费一个任务来执行,对于大部分并发场景这种策略都没有问题。但是有原创 2021-11-21 00:16:41 · 619 阅读 · 0 评论 -
并发编程设计之两阶段终止模式:如何优雅地终止线程
并发编程设计之两阶段终止模式:如何优雅地终止线程?引言如何理解两阶段终止模式用两阶段终止模式终止监控操作如何优雅地终止线程池引言“优雅地终止线程”,不是自己终止自己,而是在一个线程 T1 中,终止线程 T2;这里所谓的“优雅”,指的是给 T2 一个机会料理后事,而不是被一剑封喉。Java 语言的 Thread 类中曾经提供了一个 stop() 方法,用来终止线程,可是早已不建议使用了,原因是这个方法用的就是一剑封喉的做法,被终止的线程没有机会料理后事。如何理解两阶段终止模式两阶段终止模式。顾名思义原创 2021-11-20 22:28:01 · 513 阅读 · 0 评论 -
并发编程设计之Worker Thread模式:如何避免重复创建线程?
并发编程设计之Worker Thread模式:如何避免重复创建线程?引言Worker Thread 模式及其实现正确地创建线程池避免线程死锁引言Thread-Per-Message 模式,对应到现实世界,其实就是委托代办。这种分工模式如果用 Java Thread 实现,频繁地创建、销毁线程非常影响性能,同时无限制地创建线程还可能导致 OOM,所以在 Java 领域使用场景就受限了。要想有效避免线程的频繁创建、销毁以及 OOM 问题,就不得不提今天我们要细聊的,也是 Java 领域使用最多的 Work原创 2021-11-20 22:02:29 · 838 阅读 · 0 评论 -
并发编程设计之Thread-Per-Message模式:最简单实用的分工方法
并发编程设计之Thread-Per-Message模式:最简单实用的分工方法引言如何理解 Thread-Per-Message 模式用 Thread 实现 Thread-Per-Message 模式引言并发编程领域的问题总结为三个核心问题:分工、同步和互斥。其中,同步和互斥相关问题更多地源自微观,而分工问题则是源自宏观。我们解决问题,往往都是从宏观入手,在编程领域,软件的设计过程也是先从概要设计开始,而后才进行详细设计。同样,解决并发编程问题,首要问题也是解决宏观的分工问题。并发编程领域里,解决分工问原创 2021-11-20 21:23:19 · 281 阅读 · 0 评论 -
并发编程设计之Balking模式:再谈线程安全的单例模式
并发编程设计之Balking模式:再谈线程安全的单例模式引言Balking 模式的经典实现Balking 模式实现线程安全的单例引言上篇文章提到可以用“多线程版本的 if”来理解 Guarded Suspension 模式,不同于单线程中的 if,这个“多线程版本的 if”是需要等待的,而且还很执着,必须要等到条件为真。但很显然这个世界,不是所有场景都需要这么执着,有时候我们还需要快速放弃。我们先抛出结论,大家阅读完本文后可以和上篇文章对比分析:《并发编程设计之Guarded Suspension模原创 2021-11-20 20:41:33 · 371 阅读 · 0 评论 -
并发编程设计之Guarded Suspension模式:等待唤醒机制的规范实现
并发编程设计之Guarded Suspension模式:等待唤醒机制的规范实现引言Guarded Suspension 模式引言一个 Web 项目中,用户通过浏览器发过来一个请求,会被转换成一个异步消息发送给 MQ,等 MQ 返回结果后,再将这个结果返回至浏览器。小灰同学的问题是:给 MQ发送消息的线程是处理 Web 请求的线程 T1,但消费 MQ 结果的线程并不是线程 T1,那线程 T1 如何等待 MQ 的返回结果呢?Dubbo中用到的异步转同步就是借助条件变量Condition来实现的,这是本方原创 2021-11-20 14:30:23 · 359 阅读 · 0 评论 -
并发编程设计之线程本地存储模式:没有共享,就没有伤害
并发编程设计之线程本地存储模式:没有共享,就没有伤害引言ThreadLocal 的使用方法ThreadLocal 的工作原理ThreadLocal 与内存泄露InheritableThreadLocal 与继承性引言多个线程同时读写同一共享变量存在并发问题。前面两篇文章我们突破的是写,没有写操作自然没有并发问题了。其实还可以突破共享变量,没有共享变量也不会有并发问题,正所谓是没有共享,就没有伤害。每个线程都拥有自己的变量,彼此之间不共享,也就没有并发问题了。你已经知道通过局部变量可以做到避免共享,那还原创 2021-11-20 12:25:18 · 333 阅读 · 0 评论 -
并发编程设计之Copy-on-Write模式:不是延时策略的COW
并发编程设计之Copy-on-Write模式:不是延时策略的COW引言Copy-on-Write 模式的应用领域案例讲解引言Java 里 String 这个类在实现 replace() 方法的时候,并没有更改原字符串里面 value[] 数组的内容,而是创建了一个新字符串,这种方法在解决不可变对象的修改问题时经常用到。如果你深入地思考这个方法,你会发现它本质上是一种Copy-on-Write 方法。所谓 Copy-on-Write,经常被缩写为 COW 或者 CoW,顾名思义就是写时复制。不可变对象的写原创 2021-11-20 00:18:23 · 356 阅读 · 0 评论 -
并发编程设计之Immutability模式:如何利用不变性解决并发问题?
并发编程设计之Immutability模式:如何利用不变性解决并发问题?引言快速实现具备不可变性的类利用享元模式避免创建重复对象使用 Immutability 模式的注意事项引言解决并发问题,其实最简单的办法就是让共享变量只有读操作,而没有写操作。这个办法如此重要,以至于被上升到了一种解决并发问题的设计模式:不变性(Immutability)模式。所谓不变性,简单来讲,就是对象一旦被创建之后,状态就不再发生变化。换句话说,就是变量一旦被赋值,就不允许修改了(没有写操作)。快速实现具备不可变性的类将一原创 2021-11-19 00:12:56 · 371 阅读 · 0 评论 -
Fork/Join:原来具有复杂相似性的问题可以用分治并行处理
Fork/Join:原来具有复杂相似性的问题可以用分治并行处理引言分治任务模型Fork/Join的使用ForkJoinPool 工作原理引言对于简单的并行任务,你可以通过“线程池 +Future”的方案来解决;如果任务之间有聚合关系,无论是 AND 聚合还是 OR 聚合,都可以通过 CompletableFuture 来解决;而批量的并行任务,则可以通过 CompletionService 来解决。我们一直讲,并发编程可以分为三个层面的问题,分别是分工、协作和互斥,当你关注于任务的时候,你会发现你的原创 2021-11-15 23:51:39 · 395 阅读 · 0 评论 -
CompletionService:如何批量执行异步任务?
CompletionService:如何批量执行异步任务?引言利用 CompletionService 实现询价系统CompletionService 接口说明利用 CompletionService 实现 Dubbo 中的 Forking Cluster引言不久前听说小明要做一个询价应用,这个应用需要从三个电商询价,然后保存在自己的数据库里。核心示例代码如下所示,由于是串行的,所以性能很慢,你来试着优化一下吧。// 向电商 S1 询价,并保存r1 = getPriceByS1();save(r原创 2021-11-14 14:31:02 · 203 阅读 · 0 评论 -
CompletableFuture:了解异步很重要
CompletableFuture:了解异步很重要引言CompletableFuture 的核心优势创建 CompletableFuture 对象如何理解 CompletionStage 接口任务间的串行关系任务间的AND 汇聚关系任务间的OR 汇聚关系异常处理引言异步化,是并行方案得以实施的基础,更深入地讲其实就是:利用多线程优化性能这个核心方案得以实施的基础。看到这里,相信你应该就能理解异步编程最近几年为什么会大火了,因为优化性能是互联网大厂的一个核心需求啊。Java 在 1.8 版本提供了Com原创 2021-11-14 12:36:20 · 299 阅读 · 0 评论 -
Future:线程池提交了任务,怎么获取结果呢?
Future:线程池提交了任务,怎么获取结果呢?引言如何获取任务执行结果Future实战演练引言在上一篇文章中,我们仅仅介绍了 ThreadPoolExecutor 的 void execute(Runnable command) 方法,利用这个方法虽然可以提交任务,但是却没有办法获取任务的执行结果(execute() 方法没有返回值)。别急,本篇文章主角Future就是负责这部分的。如何获取任务执行结果Java 通过 ThreadPoolExecutor 提供的 3 个 submit() 方法和原创 2021-11-13 22:36:29 · 1199 阅读 · 0 评论 -
Executor与线程池:你真的用好线程池了吗?
Executor与线程池:你真的用好线程池了吗?引言线程池是一种生产者 - 消费者模式如何使用 Java 中的线程池使用线程池要注意些什么引言与创建对象不同,仅仅是在 JVM 的堆里分配一块内存而已;而创建一个线程,却需要调用操作系统内核的 API,然后操作系统要为线程分配一系列的资源,这个成本就很高了,所以线程是一个重量级的对象,应该避免频繁创建和销毁。那么就需要线程池来进行统一管理。线程池是一种生产者 - 消费者模式目前业界线程池的设计,普遍采用的都是生产者 - 消费者模式。线程池的使用方是生产原创 2021-11-13 22:04:30 · 75 阅读 · 0 评论 -
CAS:并发同步性不一定要靠互斥锁
CAS:并发同步性不一定要靠互斥锁引言CAS的实现原理Java中CAS的实现原子类概览引言在一个最简单的变量累加操作上,如果引入多线程执行,必然带来可见行与同步性的问题,那么通常来讲,利用volatile可以解决线程间变量的可见行,互斥锁可以实现线程间变量的同步问题。public class Test { long count = 0; void add10K() { int idx = 0; while(idx++ < 10000) { count += 1原创 2021-11-13 21:29:22 · 537 阅读 · 0 评论 -
CountDownLatch和CyclicBarrier:如何让多线程步调一致?
CountDownLatch和CyclicBarrier:如何让多线程步调一致?引言并行提高执行效率用 CountDownLatch 实现线程等待进一步优化性能CyclicBarrier 实现线程同步引言本期以一个对账系统做为背景,讲述利用CountDownLatch和CyclicBarrier两大优秀的并发工具类来对系统性能逐步优化。对账系统的处理逻辑很简单,你可以参考下面的对账系统流程图。目前对账系统的处理逻辑是首先查询订单,然后查询派送单,之后对比订单和派送单,将差异写入差异库。对账系统的代原创 2021-11-11 12:31:14 · 521 阅读 · 0 评论 -
StampedLock:比读写锁更快的锁
StampedLock:比读写锁更快的锁????StampedLock 支持的三种锁模式深入了解乐观锁使用StampedLock 需要注意什么StampedLock 支持的三种锁模式Java 在 1.8 这个版本里,提供了一种叫 StampedLock 的锁,它的性能就比读写锁还要好。StampedLock 支持三种模式,分别是:写锁、悲观读锁和乐观读。其中,写锁、悲观读锁的语义和 ReadWriteLock的写锁、读锁的语义非常类似,允许多个线程同时获取悲观读锁,但是只允许一个线程获取写锁,写锁和原创 2021-11-11 11:03:31 · 523 阅读 · 0 评论 -
ReadWriteLock:读多写少场景利器
ReadWriteLock:读多写少场景利器什么是读写锁快速实现一个缓存缓存按需加载的实现读写锁的升级与降级什么是读写锁读写锁,并不是 Java 语言特有的,而是一个广为使用的通用技术,所有的读写锁都遵守以下三条基本原则:允许多个线程同时读共享变量;只允许一个线程写共享变量;如果一个写线程正在执行写操作,此时禁止读线程读共享变量。读写锁与互斥锁的一个重要区别就是读写锁允许多个线程同时读共享变量,而互斥锁是不允许的,这是读写锁在读多写少场景下性能优于互斥锁的关键。但读写锁的写操作是互斥的,原创 2021-11-10 00:12:13 · 522 阅读 · 0 评论 -
Semaphore:限流器的底层模型你知道吗?
Semaphore:限流器的底层模型你知道吗?信号量模型Semaphore的使用限流器的实现信号量模型信号量模型可以简单概括为:一个计数器,一个等待队列,三个方法。在信号量模型里,计数器和等待队列对外是透明的,所以只能通过信号量模型提供的三个方法来访问它们,这三个方法分别是:init()、down() 和 up()。init():设置计数器的初始值。down():计数器的值减 1;如果此时计数器的值小于 0,则当前线程将被阻塞,否则当前线程可以继续执行。up():计数器的值加 1;如果此时计原创 2021-11-07 22:26:34 · 134 阅读 · 0 评论 -
Lock与Condition:解决并发的万能钥匙
Lock与Condition:解决Java并发的万能钥匙为什么再造管程Lock如何保证可见性什么是可重入锁公平与非公平锁锁的最佳实践Condition条件变量Condition在Dubbo中的应用为什么再造管程在并发编程领域,有两大核心问题:一个是互斥,即同一时刻只允许一个线程访问共享资源;另一个是同步,即线程之间如何通信、协作。这两大问题,管程都是能够解决的。Java SDK 并发包通过 Lock 和 Condition 两个接口来实现管程,其中 Lock 用于解决互斥问题,Condition 用于解原创 2021-11-07 21:06:51 · 270 阅读 · 0 评论