![](https://img-blog.csdnimg.cn/20190927151117521.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
java并发
文章平均质量分 88
java并发基础,一步一步来理解并发的来龙去脉。
df007df
帮助大家从容面对面试,弥补平时工作中因没有时间而遗忘的八股文。
提供面经突击内容,作为面试突击或补齐多年Java基本功必备。
展开
-
【Java面试突击-9】Java并发编程(AQS)
CLH锁其实就是一种是基于逻辑队列非线程饥饿的一种自旋公平锁,由于是 Craig、Landin 和 Hagersten三位大佬的发明,因此命名为CLH锁。AQS是JUC的核心,而CLH锁又是AQS的基础,说核心也不为过,因为AQS就是用了变种的CLH锁。如果要学好Java并发编程,那么必定要学好JUC;学好JUC,必定要先学好AQS;学好AQS,那么必定先学好CLH。先看CLH锁实现代码,然后通过一步一图来详解CLH锁。CLH锁的初始化逻辑1,定义了一个节点,里面有一个属性,表示线程线程是否获得锁,默认原创 2022-06-28 00:55:16 · 130 阅读 · 0 评论 -
【Java面试突击-8】Java并发编程(线程安全)
多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为。线程安全有以下四种实现方式:不可变(Immutable)的对象一定是线程安全的,不需要再采取任何的线程安全保障措施。只要一个不可变的对象被正确地构建出来,永远也不会看到它在多个线程之中处于不一致的状态。多线程环境下,应当尽量使对象成为不可变,来满足线程安全。不可变的类型:对于集合类型,可以使用 Collections.unmodifiableXXX() 方法来获取一个不可变的集合。互斥同步synchronized 和原创 2022-06-19 21:08:13 · 100 阅读 · 0 评论 -
【Java面试突击-7】Java并发编程(线程池)
线程池提供了一种限制和管理资源(包括执行一个任务)的方式。 每个线程池还维护一些基本统计信息,例如已完成任务的数量。使用线程池的好处:Executor 框架是 Java5 之后引进的,在 Java 5 之后,通过 Executor 来启动线程比使用 Thread 的 start 方法更好,除了更易管理,效率更好(用线程池实现,节约开销。Executor 框架不仅包括了线程池的管理,还提供了线程工厂、队列以及拒绝策略等,Executor 框架让并发编程变得更加简单。执行任务需要实现的 接口 或接口。 接口或原创 2022-06-07 23:03:13 · 127 阅读 · 0 评论 -
【Java面试突击-6】Java并发编程(上)
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间原创 2022-06-07 18:53:25 · 135 阅读 · 0 评论 -
[Java并发-1]入门:并发编程Bug的源头
背景介绍如何解决并发问题,首先要理解并发问题的实际源头怎么发生的。现代计算机的不同硬件的运行速度是差异很大的,这个大家应该都是知道的。计算机数据传输运行速度上的快慢比较:CPU > 缓存 > I/O如何最大化的让不同速度的硬件可以更好的协调执行,需要做一些“撮合”的工作CUP增加了高速缓存来均衡与缓存间的速度差异操作系统增加了 进程,线程,以分时复用CPU,进而均衡CPU与I/O的速度差异(当等待I/O的时候系统切换CPU给系统程序使用)现代编程语言的编译器优化指令顺序,使原创 2022-05-18 10:50:37 · 171 阅读 · 0 评论 -
[Java并发-2]Java如何解决可见性问题的
之前我们说了:1,可见性2,原子性3,有序性3个并发BUG的之源,这三个也是编程领域的共性问题。Java诞生之处就支持多线程,所以自然有解决这些问题的办法,而且在编程语言领域处于领先地位。理解Java解决并发问题的方案,对于其他语言的解决方案也有触类旁通的效果。什么是Java内存模型我们已经知道了,导致可见性的原因是缓存,导致有序性的问题是编译优化。那解决问题的办法就是直接禁用 缓存和编译优...原创 2019-03-18 00:00:00 · 86 阅读 · 0 评论 -
[Java并发-3]Java互斥锁,解决原子性问题
在前面的分享中我们提到。一个或者多个操作在 CPU 执行的过程中不被中断的特性,称为“原子性”思考:在32位的机器上对long型变量进行加减操作存在并发问题,什么原因!?原子性问题如何解决我们已经知道原子性问题是线程切换,而操作系统做线程切换是依赖 CPU 中断的,所以禁止 CPU 发生中断就能够禁止线程切换。在单核 CPU 时代,这个方案的确是可行的。这里我们以 32 位 CPU 上...原创 2019-04-10 00:00:00 · 64 阅读 · 0 评论 -
[Java并发-4]解决Java死锁的问题
在上一篇中,我们尝试使用了 Account.class作为互斥锁,来解决转账问题。但是很容易发现这样,所有的转账操作都是串行的,性能太差了。让我们尝试提升下性能。向现实世界要答案现实世界中,转账操作是支持并发的。我设想下,在古代没有信息化的时候。账户的存在就是一个个账本,而且每个用户都有一个账本。这些账本都放在架子上。银行柜员在转账时候,是去架子上同时拿到转入账本和转出账本,然后做转账都...原创 2019-04-18 00:00:00 · 73 阅读 · 0 评论 -
[Java并发-5]用“等待-通知”机制优化循环等待
由上一篇文章你应该已经知道,在 破坏占用且等待条件 的时候,如果转出账本和转入账本不满足同时在文件架上这个条件,就用死循环的方式来循环等待,核心代码如下:// 一次性申请转出账户和转入账户,直到成功while(!actr.apply(this, target)) ;如果 apply() 操作耗时非常短,而且并发冲突量也不大时,这个方案还挺不错的,因为这种场景下,循环上几次或者几十次就能...原创 2019-04-19 00:00:00 · 61 阅读 · 0 评论 -
[Java并发-6]“管程”-java管程初探
并发编程这个技术领域已经发展了半个世纪了。有没有一种核心技术可以很方便地解决我们的并发问题呢?这个问题, 我会选择 Monitor(管程)技术。Java 语言在 1.5 之前,提供的唯一的并发原语就是管程,而且 1.5 之后提供的 SDK 并发包,也是以管程技术为基础的。除此之外,C/C++、C# 等高级语言也都支持管程。什么是管程操作系统原理课程告诉我们,用信号量能解决所有并发问题。但是为...原创 2019-04-27 00:00:00 · 79 阅读 · 0 评论 -
[Java并发-7]java的线程小节
在 Java 领域,实现并发程序的主要手段就是多线程。线程是操作系统里的一个概念,虽然各种不同的开发语言如 Java、C# 等都对其进行了封装,但原理和思路都是相同都。Java 语言里的线程本质上就是操作系统的线程,它们是一一对应的。在操作系统层面,线程也有“生老病死”,专业的说法叫有生命周期。对于有生命周期的事物,要学好它,只要能搞懂生命周期中各个节点的状态转换机制就可以了。虽然不同的开发...原创 2019-05-11 00:00:00 · 66 阅读 · 0 评论 -
[Java并发-8]Lock和Condition(上) 隐藏在并发包中的管程
Java SDK 并发包内容很丰富。但是最核心的还是其对管程的实现。因为理论上利用管程,你几乎可以实现并发包里所有的工具类。在前面我们提到过在并发编程领域,有两大核心问题:一个是互斥:即同一时刻只允许一个线程访问共享资源;另一个是 同步:即线程之间如何通信、协作。这两大问题,管程都是能够解决的。Java SDK 并发包通过 Lock 和 Condition 两个接口来实现管程,其中 Lock ...原创 2019-05-12 00:00:00 · 57 阅读 · 0 评论 -
[Java并发-9]Lock和Condition(下) Dubbo如何用管程实现异步转同步?
在上一篇文章中,我们讲到 Java SDK 并发包里的 Lock 有别于 synchronized 隐式锁的三个特性:能够响应中断、支持超时和非阻塞地获取锁。那今天我们接着再来详细聊聊 Java SDK 并发包里的 Condition。Condition 实现了管程模型里面的条件变量在之前我们详细讲过, Java 语言内置的管程里只有一个条件变量,而 Lock&Condition 实...原创 2019-05-12 00:00:00 · 66 阅读 · 0 评论 -
[Java并发-10] ReadWriteLock:快速实现一个完备的缓存
大家知道了Java中使用管程同步原语,理论上可以解决所有的并发问题。那 Java SDK 并发包里为什么还有很多其他的工具类呢?原因很简单:分场景优化性能,提升易用性今天我们就介绍一种非常普遍的并发场景:读多写少场景。实际工作中,为了优化性能,我们经常会使用缓存,例如缓存元数据、缓存基础数据等,这就是一种典型的读多写少应用场景。缓存之所以能提升性能,一个重要的条件就是缓存的数据一定是读多写少的...原创 2019-05-13 00:00:00 · 80 阅读 · 0 评论 -
[Java并发-11] 并发容器的使用
Java 并发包有很大一部分内容都是关于并发容器的,因此学习和搞懂这部分的内容很有必要。Java 1.5 之前提供的同步容器虽然也能保证线程安全,但是性能很差,而 Java 1.5 版本之后提供的并发容器在性能方面则做了很多优化,并且容器的类型也更加丰富了。下面我们就对比二者来学习这部分的内容。同步容器及其注意事项Java 中的容器主要可以分为四个大类,分别是 List、Map、Set 和...原创 2019-05-26 00:00:00 · 71 阅读 · 0 评论 -
[Java并发-12] 原子类:无锁工具类的典范
前面我们多次提到一个累加器的例子,示例代码如下。在这个例子中,add10K() 这个方法不是线程安全的,问题就出在变量 count 的可见性和 count+=1 的原子性上。可见性问题可以用 volatile 来解决,而原子性问题我们前面一直都是采用的互斥锁方案。public class Test { long count = 0; void add10K() { int id...原创 2019-06-16 00:00:00 · 63 阅读 · 0 评论 -
[Java并发-13] ThreadPoolExecutor: 如何创建正确的线程池
虽然在 Java 语言中创建线程看上去就像创建一个对象一样简单,只需要 new Thread() 就可以了,但实际上创建线程远不是创建一个对象那么简单。创建对象,仅仅是在 JVM 的堆里分配一块内存而已;而创建一个线程,却需要调用操作系统内核的 API,然后操作系统要为线程分配一系列的资源,这个成本就很高了,所以线程是一个重量级的对象,应该避免频繁创建和销毁那如何避免呢?应对方案估计你已经知道了...原创 2019-06-23 00:00:00 · 77 阅读 · 0 评论 -
[Java并发-14] Future: 优雅的使用多线程
上一篇,我们详细介绍了如何创建正确的线程池,那创建完线程池,我们该如何使用呢?在上一篇文章中,我们仅仅介绍了 ThreadPoolExecutor 的 void execute(Runnable command) 利用这个方法虽然可以提交任务,但是却没有办法获取任务的执行结果(execute() 方法没有返回值)。而很多场景下,我们又都是需要获取任务的执行结果的。下面我们就来介绍一下使用 Th...原创 2019-06-23 00:00:00 · 123 阅读 · 0 评论 -
[Java并发-15] CompletableFuture: 异步编程
前面我们不止一次提到,用多线程优化性能,其实不过就是将串行操作变成并行操作。如果仔细观察,你还会发现在串行转换成并行的过程中,一定会涉及到异步化,例如下面的示例代码,现在是串行的,为了提升性能,我们得把它们并行化。// 以下两个方法都是耗时操作doBizA();doBizB();//创建两个子线程去执行就可以了,两个操作已经被异步化了。new Thread(()->doBiz...原创 2019-06-25 00:00:00 · 68 阅读 · 0 评论 -
[Java并发-16] CompletionService:批量执行异步任务
我们思考下这个场景:从三个电商询价,然后保存在自己的数据库里。通过之前所学,我们可能这么实现。// 创建线程池ExecutorService executor = Executors.newFixedThreadPool(3);// 异步向电商 S1 询价Future<Integer> f1 = executor.submit( ()->getPric...原创 2019-06-27 00:00:00 · 116 阅读 · 0 评论 -
[Java并发-17-并发设计模式] Immutability模式:如何利用不变性解决并发问题?
解决并发问题,其实最简单的办法就是让共享变量只有读操作,而没有写操作。这个办法如此重要,以至于被上升到了一种解决并发问题的设计模式:不变性(Immutability)模式。所谓不变性,简单来讲,就是对象一旦被创建之后,状态就不再发生变化。换句话说,就是变量一旦被赋值,就不允许修改了(没有写操作);没有修改操作,也就是保持了不变性。快速实现具备不可变性的类实现一个具备不可变性的类,还是挺简单的...原创 2019-07-04 00:00:00 · 79 阅读 · 0 评论 -
[Java并发-18-并发设计模式] COW模式:Copy-on-Write模式的应用领域
在上一篇文章中我们讲到 Java 里 String 这个类在实现 replace() 方法的时候,并没有更改原字符串里面 value[] 数组的内容,而是创建了一个新字符串,这种方法在解决不可变对象的修改问题时经常用到。如果你深入地思考这个方法,你会发现它本质上是一种Copy-on-Write 方法。所谓 Copy-on-Write,经常被缩写为 COW 或者 CoW,顾名思义就是写时复制。不...原创 2019-07-04 00:00:00 · 102 阅读 · 0 评论 -
[Java并发-19-并发设计模式] ThreadLocal | 线程本地存储模式
我们曾经重复说到,多个线程同时读写同一共享变量存在并发问题。前面两篇文章我们突破的是写,没有写操作自然没有并发问题了。其实还可以突破共享变量,没有共享变量也不会有并发问题。那如何避免共享呢?思路其实很简单,并发编程领域,就是每个线程都拥有自己的变量,彼此之间不共享,也就没有并发问题了。我们知道局部变量可以做到避免共享, 即线程封闭,其本质上就是避免共享。那还有没有其他方法可以做到呢?有的Ja......原创 2019-07-09 00:00:00 · 197 阅读 · 0 评论 -
[Java并发-20-并发设计模式] Guarded Suspension模式:等待唤醒机制的规范实现
在开发中我们或许回遇到这样的情况:有一个Web 版的文件浏览器,通过它用户可以在浏览器里查看服务器上的目录和文件。这个项目依赖运维部门提供的文件浏览服务,而这个文件浏览服务只支持消息队列(MQ)方式接入。消息队列在互联网大厂中用的非常多,主要用作流量削峰和系统解耦。在这种接入方式中,发送消息和消费结果这两个操作之间是异步的,你可以参考下面的示意图来理解。消息队列(MQ)示意图在这个 Web ...原创 2019-07-09 00:00:00 · 56 阅读 · 0 评论 -
[Java并发-21-并发设计模式] Balking模式:线程安全的单例模式
上一篇文章中,我们提到可以用“多线程版本的 if”来理解 Guarded Suspension 模式,不同于单线程中的 if,这个“多线程版本的 if”是需要等待的,而且还很执着,必须要等到条件为真。但很显然这个世界,不是所有场景都需要这么执着,有时候我们还需要快速放弃。需要快速放弃的一个最常见的例子是各种编辑器提供的自动保存功能。自动保存功能的实现逻辑一般都是隔一定时间自动执行存盘操作,存盘...原创 2019-07-12 00:00:00 · 77 阅读 · 0 评论 -
[Java并发-22-并发设计模式] Thread-Per-Message 与 Worker Thread 模式
我们曾经把并发编程领域的问题总结为三个核心问题:分工、同步和互斥。其中,同步和互斥相关问题更多地源自微观,而分工问题则是源自宏观。我们解决问题,往往都是从宏观入手,同样,解决并发编程问题,首要问题也是解决宏观的分工问题。并发编程领域里,解决分工问题也有一系列的设计模式,比较常用的主要有 Thread-Per-Message 模式、Worker Thread 模式、生产者 - 消费者模式等等。今...原创 2019-07-12 00:00:00 · 1216 阅读 · 0 评论 -
[Java并发-23-并发设计模式] 两阶段终止模式:优雅地终止线程
前面我们都是在讲如何创建线程,接下来我们说下如何终止线程。java的线程小节中,我曾讲过:线程执行完或者出现异常就会进入终止状态。这样看,终止一个线程看上去很简单啊!一个线程执行完自己的任务,自己进入终止状态,这的确很简单。不过我们今天谈到的“优雅地终止线程”,不是自己终止自己,而是在一个线程 T1 中,终止线程 T2;这里所谓的“优雅”,指的是给 T2 一个机会料理后事,而不是被直接终止。...原创 2019-07-15 00:00:00 · 59 阅读 · 0 评论 -
[Java并发-24-并发设计模式] 生产者-消费者模式,并发提高效率
生产者 - 消费者模式在编程领域的应用非常广泛,前面我们曾经提到,Java 线程池本质上就是用生产者 - 消费者模式实现的,所以每当使用线程池的时候,其实就是在应用生产者 - 消费者模式。当然,除了在线程池中的应用,为了提升性能,并发编程领域很多地方也都用到了生产者 - 消费者模式,例如 Log4j2 中异步 Appender 内部也用到了生产者 - 消费者模式。所以我们就来深入地聊聊生产者 ...原创 2019-07-15 00:00:00 · 68 阅读 · 0 评论 -
[Java并发-25] 高性能数据库连接池 HiKariCP 分析
实际工作中,我们总会难免和数据库打交道;只要和数据库打交道,就免不了使用数据库连接池。业界知名的数据库连接池有不少,例如 DBCP、Tomcat JDBC Connection Pool、Druid 等,不过最近最火的是 HiKariCP。HiKariCP 号称是业界跑得最快的数据库连接池,尤其是 Springboot 2.0 将其作为默认数据库连接池后,地位已是毋庸置疑了。那它为什么那么快呢...原创 2019-07-16 00:00:00 · 116 阅读 · 0 评论 -
[Java并发-26] 软件事务内存:借鉴数据库的并发经验
实际上我们天天都在写并发程序,只不过并发相关的问题都被类似 Tomcat 这样的 Web 服务器以及 MySQL 这样的数据库解决了。尤其是数据库,在解决并发问题方面,可谓博大精深,它的事务机制非常简单易用,能甩 Java 里面的锁、原子类十条街。很显然对于我们要借鉴一下。其实很多编程语言都有从数据库的事务管理中获得灵感,并且总结出了一个新的并发解决方案:软件事务内存(Software Tra...原创 2019-07-19 00:00:00 · 129 阅读 · 0 评论 -
[学习笔记-Java并发源码] 目录
本系列开始记录针对java并发体系的相关源码学习。大部分来之网络内容,只是自己整理与总结之用。synchronizedsynchronized的实现原理volatile的实现原理AQS...原创 2019-08-31 00:00:00 · 58 阅读 · 0 评论 -
[学习笔记-Java并发源码-1] synchronized的实现原理
在Java中,如果一遇到多线程情况需要解决,我们想到最多的可能就是synchronized。或者叫它“同步”,很早以前或许synchronized是一个重量级锁,相对于Lock,它会显得那么笨重,以至于我们慢慢摒弃它。但是早在 Javs SE 1.6及以后的版本,对synchronized进行的各种优化后,synchronized的性能得到了明细的提升。下面就来看看,synchronized...原创 2019-08-31 00:00:00 · 79 阅读 · 0 评论 -
[学习笔记-Java并发源码-2] volatile的实现原理
目录目录大纲:内存模型的相关概念并发编程中的三个概念原子性可见性有序性小结Java内存模型原子性可见性有序性深入剖析volatile关键字volatile关键字的两层语义volatile的原子性volatile的有序性volatile 内存语义的实现使用volatile关键字的场景 状态标记量double check volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在Java 5之后,volatile关键原创 2019-09-02 00:00:00 · 122 阅读 · 0 评论