
Java并发编程
文章平均质量分 88
一起攻克JUC吧
JavaEdge聊AI
关注并私信我,获取更多大厂求职经验。《编程严选网》创始人
展开
-
互联网大厂电商业务,扣库存操作究竟该如何加锁?
购物车添加商品的逻辑,随机添加三种商品,假设一个购物车中的商品是item1和item2,另一个购物车中的商品是item2和item1,一个线程先获取到了item1的锁,同时另一个线程获取到了item2的锁,然后两个线程接下来要分别获取item2和item1的锁,这个时候锁已经被对方获取了,只能相互等待一直到10s超时。虽然死锁,但因为尝试获取锁的操作并非无限阻塞,所以没有造成永久死锁,之后的改进就是避免循环等待,通过对购物车的商品进行排序来实现有顺序的加锁,避免循环等待。直接把wrong定义为静态不就行?原创 2020-11-07 01:23:47 · 2660 阅读 · 0 评论 -
Java 并发编程实战-创建和执行任务的最佳实践
若无法通过并行流实现并发,则必须创建并运行自己的任务。运行任务的理想Java 8方法就是CompletableFuture。Java并发的历史始于非常原始和有问题的机制,并且充满各种尝试的优化。本文将展示一个规范形式,表示创建和运行任务的最简单,最好的方法。Java初期通过直接创建自己的Thread对象来使用线程,甚至子类化来创建特定“任务线程”对象。手动调用构造函数并自己启动线程。创建所有这些线程的开销变得非常重要,现在不鼓励。Java 5中,添加了类来为你处理线程池。可以将任务创建为单独的类型,然后原创 2022-04-23 21:21:10 · 2351 阅读 · 2 评论 -
万字总结!全网最全的Java并发编程知识点
#1 基本概念##1.1 并发同时拥有两个或者多个线程,如果程序在单核处理器上运行多个线程将交替地换入或者换出内存,这些线程是同时“存在"的,每个线程都处于执行过程中的某个状态,如果运行在多核处理器上,此时,程序中的每个线程都将分配到一个处理器核上,因此可以同时运行.##1.2 高并发( High Concurrency)互联网分布式系统架构设计中必须考虑的因素之一,通常是指,通过设计保证系统能够同时并行处理很多请求.##1.3 区别与联系并发: 多个线程操作相同的资源,保证线程安全,合...原创 2021-09-16 16:21:57 · 3439 阅读 · 8 评论 -
Java集合源码解析-ConcurrentHashMap(JDK8)
8 为并发而生的 ConcurrentHashMap(Java 8)8.1 数据结构Java 7为实现并发访问,引入了Segment这一结构,实现了分段锁,理论上最大并发度与Segment个数相等。Java 8取消了基于 Segment 的分段锁思想,改用CAS + synchronized 控制并发操作;在某些方面提升了性能;并且追随 1.8 版本的 HashMap 底层实现,使用数组+链表+红黑树进行数据存储.和 HashMap 中的语义一样,代表整个哈希表这是一个连接表,用原创 2021-07-05 13:49:48 · 2532 阅读 · 28 评论 -
【Java并发编程实战14】构建自定义同步工具(Building-Custom-Synchronizers)
JDK包含许多存在状态依赖的类,例如FutureTask、Semaphore和BlockingQueue,他们的一些操作都有前提条件,例如非空、任务已完成等。创建状态依赖类的最简单的房就是在JDK提供了的状态依赖类基础上构造。例如ValueLactch,如果这些不满足,可以使用Java语言或者类库提供的底层机制来构造,包括内置的条件队列conditionAQS这一章就介绍这些。14.1 状态依赖性的管理 State Dependence在14.2节会介绍使用条件队列来解决阻塞线程运行的问题原创 2021-06-23 14:43:49 · 1152 阅读 · 4 评论 -
【大厂Java并发编程面试题解】显式锁(Explicit Locks)
Java5之前只能用synchronized和volatile,5后Doug Lea加入了ReentrantLock,并不是替代内置锁,而是当内置锁机制不适用时,作为一种可选择的高级功能不适用包括无法中断一个正在等待获取锁的线程无限的锁等待内置锁必须放在代码块里面(编程有些局限性)所以提供了J.U.C的Lock1. Lock和ReentrantLock之所以叫ReentrantLock,可理解为两部分Re-entrant可重入,lock多少次都没关系,只需要unlock即可,或原创 2021-06-05 15:49:59 · 1897 阅读 · 12 评论 -
【并发编程神器】,Worker Thread模式
如何才能有效避免线程的频繁创建、销毁以及OOM?Java应用最多的就是Worker Thread模式(后文简称为 WT)。如何实现WT?WT类比程序员的工作场景:办公室里的执行 OKR 的程序员们,如果产品需求池有任务了,大家一起分任务,需求池空了(有生之年基本不会空)就摸鱼。画个示意图理解下,WT 中的 Worker Thread对应我们程序员,一个团队的程序员数量往往固定。编程中如何模拟这种模式呢?容易想到用阻塞队列做需求池,然后创建固定数量的线程消费阻塞队列中的任务。这其实就是Ja.原创 2021-05-19 16:10:11 · 1684 阅读 · 7 评论 -
2021 面试还不知道如何优雅关闭Java线程?
JAVA媒体提供任务机制来安全的终止线程。但是它提供了中断(interruption),这是一种写作机制,能够使一个线程终止另外一个线程。一般来说没人希望立即终止,因为必要时总要先清理再终止。开发一个应用能够妥善处理失败、关闭、取消等过程非常 重要也有挑战。任务取消一定不要使用Thread.stop和suspend这些机制。一种协作机制就是“标记位”。例如使用volatile类型的field来保存取消状态。@ThreadSafepublic class PrimeGenerator imple原创 2021-05-09 14:05:39 · 1723 阅读 · 6 评论 -
这次彻底搞懂并发编程的Balking模式
“多线程版本的if”来理解Guarded Suspension模式,不同于单线程中的if,这个“多线程版本的if”是需要等待的,而且还很执着,必须要等到条件为真。但很显然这个世界,不是所有场景都需要这么执着,有时候我们还需要快速放弃。需要快速放弃的一个最常见的例子是各种编辑器提供的自动保存功能。自动保存功能的实现逻辑一般都是隔一定时间自动执行存盘操作,存盘操作的前提是文件做过修改,如果文件没有执行过修改操作,就需要快速放弃存盘操作。下面的示例代码将自动保存功能代码化了,很显然AutoSaveEditor原创 2021-04-29 09:53:54 · 1131 阅读 · 4 评论 -
阿里P8级大佬详解并发编程里的设计模式之Guarded Suspension
Web文件浏览器,通过它用户可以在浏览器里查看服务器上的目录和文件。这个项目依赖运维部门提供的文件浏览服务,而这个文件浏览服务只支持MQ接入。在这种接入方式中,发送消息和消费结果这两个操作之间是异步的,你可以参考下面的示意图来理解。MQ示意图用户通过浏览器发过来一个请求,会被转换成一个异步消息发送给MQ,等MQ返回结果后,再将这个结果返回至浏览器。给MQ发送消息的线程是处理Web请求的线程T1,但消费MQ结果的线程并不是线程T1,那线程T1如何等待MQ的返回结果呢?class Message{原创 2021-04-25 13:50:47 · 1366 阅读 · 3 评论 -
阿里四轮面试遭遇StampedLock,这么应对保拿offer
StampedLock的使用看上去有点复杂,但是如果你能理解乐观锁背后的原理,使用起来还是比较流畅的。建议你认真揣摩Java的官方示例,这个示例基本上就是一个最佳实践。我们把Java官方示例精简后,形成下面的代码模板,建议你在实际工作中尽量按照这个模板来使用StampedLock。// 乐观读 long stamp = sl . tryOptimisticRead();// 读入方法局部变量 . . . . . . // 校验stamp if(!原创 2021-04-24 18:25:06 · 1582 阅读 · 1 评论 -
今夜和学妹的深入交流,我彻底掌握了ReadWriteLock精髓!
了解读写锁吗?互联网的并发场景大多是读多写少。所以缓存技术使用普遍。JUC也提供了读写锁-ReadWriteLock。那你说说什么是读写锁?读写锁一般遵循以下设计原则:允许多个线程同时读共享变量只允许一个线程写共享变量如果一个写线程正在执行写操作,此时禁止读线程读共享变量。知道读写锁与互斥锁的区别吗?读写锁允许多个线程同时读共享变量,而互斥锁不允许。这也是读多写少时读写锁的优势。读写锁的写是互斥的,当一个线程在写共享变量时,其他线程不允许执行写或读。知道如何使用Read.原创 2021-04-22 17:25:58 · 2695 阅读 · 11 评论 -
刚拿到阿里offer,还热乎的信号量模型semaphore面经
Semaphore,信号量,线程能不能执行,要看信号量是不是允许。下面我们首先介绍信号量模型,之后介绍如何使用信号量,最后我们再用信号量来实现一个限流器。信号量模型信号量模型还是很简单的,可以简单概括为:一个计数器,一个等待队列,三个方法。在信号量模型里,计数器和等待队列对外是透明的,所以只能通过信号量模型提供的三个方法来访问它们,这三个方法分别是:init()、down()和up()。你可以结合下图来形象化地理解。信号量模型图这三个方法详细的语义具体如下所示。init():设置计数器的初始值。原创 2021-04-22 12:25:36 · 3037 阅读 · 6 评论 -
Java的Condition接口最正确的理解方式
Condition实现了管程模型里面的条件变量。Java 语言内置的管程里只有一个条件变量,而Lock&Condition实现的管程是支持多个条件变量的,这是二者的一个重要区别。在很多并发场景下,支持多个条件变量能够让我们的并发程序可读性更好,实现起来也更容易。例如,实现一个阻塞队列,就需要两个条件变量。那如何利用两个条件变量快速实现阻塞队列呢?一个阻塞队列,需要两个条件变量,一个是队列不空(空队列不允许出队),另一个是队列不满(队列已满不允许入队),这个例子我们前面在介绍管程的时候详细说过原创 2021-04-21 14:50:16 · 7833 阅读 · 13 评论 -
阿里P8面试扯了半小时:Java的Lock接口到底有什么用?
理论上利用管程,几乎可以实现并发包里所有的工具类。在并发编程领域,有两大核心问题:互斥同一时刻只允许一个线程访问共享资源同步线程之间如何通信、协作。这两问题,管程都能解决。并发包通过Lock和Condition两个接口来实现管程Lock解决互斥问题Condition用于解决同步问题Java语言本身提供的synchronized也是管程的一种实现,既然Java从语言层面已经实现了管程了,那为什么还要在SDK里提供另外一种实现呢?难道Java标准委员会还“重复造轮子”?显然它们之间是有原创 2021-04-21 10:11:19 · 4344 阅读 · 14 评论 -
和阿里P8大佬面试互怼了半小时的Fork/Join的原理!
只听到P8大佬在我耳边问话:谈谈对JDK并发工具的认识?我开始仔细梳理多年的并发八股文积累的经验,道:线程池、Future、CompletableFuture和CompletionService这些并发工具都帮助SE站在任务角度解决并发问题,而非纠结于线程之间协作的细节,比如线程之间如何实现等待、通知。简单并行任务线程池+Future 组合拳解决任务之间有聚合关系AND、OR聚合,都可以CompletableFuture一招鲜解决批量的并行任务CompletionService一把梭方案原创 2021-04-20 17:17:19 · 9324 阅读 · 21 评论 -
教校花学妹JDK批量异步任务最强工具CompletionService
如何优化一个询价应用的核心代码?如果采用“ThreadPoolExecutor+Future”的方案,你的优化结果很可能是下面示例代码这样:用三个线程异步执行询价,通过三次调用Future的get()方法获取询价结果,之后将询价结果保存在数据库中。// 创建线程池ExecutorService executor =Executors.newFixedThreadPool(3);// 异步向电商S1询价Future f1 =executor.submit(()->getPriceByS1(原创 2021-04-18 23:49:03 · 2010 阅读 · 8 评论 -
手把手教学妹CompletableFuture异步化,性能关系直接起飞!
Guava 的冲击由于 JDK1.5 Futrure 的 get 方法获取任务结果必须阻塞等待,Google 看不下去了,开发了 Guava 库 public static void main(String[] args) throws Exception { // 装饰器模式 ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(2原创 2021-04-18 10:42:32 · 2833 阅读 · 7 评论 -
由于不知道Java线程池的bug,某程序员叕被祭天
我们会使用各种池化技术缓存 创建性能开销较大的 对象,比如线程池、连接池、内存池。它们的原理都是预先创建一些对象入池,使用时直接取出,用完归还以复用,还会通过策略调整池中缓存对象的数量,实现动态伸缩性。由于线程的创建比较昂贵,短平快的任务一般考虑使用线程池处理,而非直接创建线程。手动声明线程池JDK的Executors工具类定义了很多便捷的方法可以快速创建线程池。但是阿里有话说:我们来看他说的弊端案例真的这么严重吗?newFixedThreadPool 可能 OOM我们写一段测试代码,来原创 2020-12-21 15:01:04 · 22187 阅读 · 34 评论 -
Java并发编程实战系列(15)-原子遍历与非阻塞同步机制
近年在并发算法领域的大多数研究都侧重于非阻塞算法,这种算法用底层的原子机器指令来代替锁来确保数据在并发访问中的一致性,非阻塞算法被广泛应用于OS和JVM中实现线程/进程调度机制和GC以及锁,并发数据结构中。与锁的方案相比,非阻塞算法都要复杂的多,他们在可伸缩性和活跃性上(避免死锁)都有巨大优势。非阻塞算法,顾名思义,多个线程竞争相同的数据时不会发生阻塞,因此他能在粒度更细的层次上进行协调,而且极大的减少调度开销。1 锁的劣势独占,可见性是锁要保证的。许多JVM都对非竞争的锁获取和释放做了很多优化,原创 2020-12-17 11:45:53 · 1174 阅读 · 0 评论 -
面试阿里被P8质问:ConcurrentHashMap真的线程安全吗?
没有啥深入实践的理论派同学,在使用并发工具时,总是认为把HashMap改为ConcurrentHashMap,就完美解决并发了呀。或者使用写时复制的CopyOnWriteArrayList,性能更佳呀!技术言论虽然自由,但面对魔鬼面试官时,我们更在乎的是这些真的正确吗?诚然,JDK 并发工具是优秀的。但也是建立在使用者清楚其适用场景基础上,才能最大发挥并发性能。1 线程重用导致用户信息错乱生产环境中,有时获取到的用户信息是别人的。查看代码后,发现是使用了ThreadLocal缓存获取到的用户信息。T原创 2020-10-27 23:00:18 · 3034 阅读 · 1 评论 -
使用CAS、FAA实现无锁编程
锁是有一定性能损失的,如果发生过多锁等待,将会非常影响程序性能。在特定情况可使用硬件同步原语替代锁,保证和锁一样数据安全,同时更好性能。使用硬件同步原语来代替锁,在一个日志上(你可以理解为消息队列中的一个队列或者分区),保证严格顺序的前提下,实现了多线程并发写入。今天,我们就来学习一下,如何用硬件同步原语(CAS)替代锁?硬件同步原语(Atomic Hardware Primitives)由计算机硬件提供的一组原子操作,较常用的原语主要是CAS和FAA两种。CAS(Compare and Swa原创 2020-08-09 19:06:57 · 1672 阅读 · 0 评论 -
Java长度为0的阻塞对列-TransferQueue详解
Java7中加入了JSR 166y规范对集合类和并发类库的改进。其中的一项是增加了接口TransferQueue和其实现类LinkedTransferQueue。TransferQueue继承了BlockingQueue并扩展了一些新方法。BlockingQueue(和Queue)是Java 5中加入的接口,它是指这样的一个队列:当生产者向队列添加元素但队列已满时,生产者会被阻塞;当消费者从队...原创 2020-04-05 21:26:45 · 3017 阅读 · 6 评论 -
阿里三面:说说线程封闭与ThreadLocal的关系
1 线程封闭多线程访问共享可变数据时,涉及到线程间数据同步的问题。并不是所有时候,都要用到共享数据,所以线程封闭概念就提出来了。数据都被封闭在各自的线程之中,就不需要同步,这种通过将数据封闭在线程中而避免使用同步的技术称为线程封闭。避免并发异常最简单的方法就是线程封闭即 把对象封装到一个线程里,只有该线程能看到此对象;那么该对象就算非线程安全,也不会出现任何并发安全问题.1.1 栈...原创 2020-03-24 14:24:20 · 2569 阅读 · 4 评论 -
万字总结最全Java线程池ThreadPoolExecutor面试题
1 为什么要用线程池1.1 线程the more, the better1、线程在java中是一个对象,更是操作系统的资源,线程创建、销毁都需要时间。如果创建时间+销毁时间>执行任务时间就很不合算2、Java对象占用堆内存,操作系统线程占用系统内存,根据JVM规范,一个线程默认最大栈大小1M,这个栈空间是需要从系统内存中分配的。线程过多,会消耗很多的内存3、操作系统需要频繁切换线程...原创 2020-03-05 16:54:22 · 2363 阅读 · 3 评论 -
Java协作中断机制
1. 引言当我们点击某个杀毒软件的取消按钮来停止查杀病毒时,当我们在控制台敲入 quit 命令以结束某个后台服务时……都需要通过一个线程去取消另一个线程正在执行的任务。Java 没有提供一种安全直接的方法来停止某个线程,但是 Java 提供了中断机制。如果对 Java 中断没有一个全面的了解,可能会误以为被中断的线程将立马退出运行,但事实并非如此。中断机制是如何工作的?捕获或检测到中断后,...转载 2020-02-13 20:44:37 · 2738 阅读 · 1 评论 -
为什么需要学习并发编程?
并发编程的掌握过程并不容易。我相信为了解决这个问题,你也听别人总结过并发编程的第一原则,那就是不要写并发程序。这个原则在我刚毕业的那几年曾经是行得通的,那个时候多核服务器还是一种奢侈品,系统的并发量也很低,借助数据库和类似Tomcat这种中间件,我们基本上不用写并发程序。或者说,并发问题基本上都被中间件和数据库解决了。但是最近几年,并发编程已经慢慢成为一项必备技能。这主要是硬件的驱动以及国...转载 2020-02-12 22:00:25 · 3056 阅读 · 0 评论 -
Java同步器之AbstractOwnableSynchronizer详解
JDK 6 时提供。一种同步器,可以由一个线程独占。该类提供了创建锁和相关同步器的基础,这些同步器可能包含所有权的概念。AbstractOwnableSynchronizer类本身并不管理或使用这些信息。但是,子类和工具可以使用适当维护的值来帮助控制和监视访问并提供诊断。public abstract class AbstractOwnableSynchronizer implemen...原创 2020-02-10 23:21:10 · 2766 阅读 · 1 评论 -
Java线程组ThreadGroup
1 简介线程组(ThreadGroup)是一个线程集合。是为了更方便地管理线程。线程组是父子结构的,一个线程组可以集成其他线程组,同时也可以拥有其他子线程组。从结构上看,线程组是一个树形结构,每个线程都隶属于一个线程组,线程组又有父线程组,这样追溯下去,可以追溯到一个根线程组——System线程组。2 线程组树的结构JVM创建的system线程组是用来处理JVM的系统任务的线程组,例如对象...原创 2020-02-10 22:00:55 · 2781 阅读 · 0 评论 -
Callable和Future
原文链接译文链接 译者:Greenster 校对:沈义扬Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理。Thread类、Runnable接口和Java内存管理模型使得多线程编程简单直接。但正如之前提到过的,Thread类和Runnable接口都不允许声明检查型异常,也不能定义返回值。没有返回值这点稍微有点麻烦。不能声明抛出检查型异常则更麻烦...转载 2020-02-07 22:49:40 · 2021 阅读 · 0 评论 -
Java 中的伪共享详解及解决方案
1. 什么是伪共享CPU 缓存系统中是以缓存行(cache line)为单位存储的。目前主流的 CPU Cache 的 Cache Line 大小都是 64 Bytes。在多线程情况下,如果需要修改“共享同一个缓存行的变量”,就会无意中影响彼此的性能,这就是伪共享(False Sharing)。2. 缓存行由于共享变量在 CPU 缓存中的存储是以缓存行为单位,一个缓存行可以存储多个变量...原创 2020-01-09 22:05:44 · 2169 阅读 · 0 评论 -
Java线程等待、唤醒通信机制详解
要想实现多个线程之间的协同,如:线程执行先后顺序、获取某个线程执行的结果等等。涉及到线程之间相互通信,分为下面四类:1 文件共享2 网络共享socket编程问题,非本文重点,不再赘述3 共享变量4 线程协作 - JDK API细分为: suspend/resume 、 wait/notify、 park/unparkJDK中对于需要多线程协作完成某一任务的场景,提供了对应API...原创 2019-10-08 03:52:45 · 1725 阅读 · 1 评论 -
Java高性能编程实战 - 线程终止
0 相关源码1 虚假的线程中止- StopStop:中止线程,并且清除监控器锁的信息,但是可能导致线程安全问题,JDK不建议用。Destroy: JDK未实现该方法理想输出I=1 j=1程序执行结果没有保证同步代码块里面数据的一致性,破坏了线程安全2 真正的线程终止2.1 interrupt如果目标线程在调用Object class 的wait()wait(...原创 2019-08-29 23:00:07 · 1697 阅读 · 0 评论 -
终结任务
线程状态新建(new):当线程被创建时,线程会短暂地处于这种状态。此时,线程已经被分配了必需的系统资源并执行了初始化。此刻线程已有资格获得CPU时间,之后调度器将把这个线程转变为可运行或阻塞状态就绪(Runnable):在此状态下,只要调度器将时间片分配给线程,线程就可以运行。在任意时刻,线程可运行也可不运行.阻塞(Blocked):线程能够运行,但某个条件阻碍了运行。当线程处此状态时,调度器原创 2017-12-10 12:47:51 · 1143 阅读 · 0 评论 -
Lock锁
Lock接口锁是用来控制多个线程访问共享资源的方式 一般来说,锁能够防止多个线程同时访问共享资源(但也有的锁可以允许多个线程访问共享资源,比如读写锁) 在Lock接口出现前,靠synchronized实现锁功能,但是在Java5之后并发包中新增了Lock接口(及其相关实现类)来实现锁功能.它提供了与synchronized类似的同步功能,只是Lock需要显示的获取和释放锁,虽然缺少了隐式获取释放原创 2017-12-03 22:45:31 · 1202 阅读 · 0 评论 -
Callable接口探究
一种具有类型参数的泛型,类型参数表示的是从call()中返回的值) 创建接口的思路 1)创建Callable实现类+重写call; 2)借助执行调度服务ExecutorService,获取Future对象: -ExecutorService ser = Executors。newFixedThreadpool(2); -Future result = ser.submit(实现类对象)转载 2017-12-03 17:04:04 · 1241 阅读 · 0 评论 -
并发编程常用方法
静态的Thread.yield()方法 当调用yield()时,对线程调度器的一种建议,它在声明:我已经执行完生命周期中最重要的部分了,此刻正是切换给其他线程的大好时机 但是这完全是选择性的,并非一定切换原创 2017-12-03 16:41:29 · 1379 阅读 · 0 评论 -
对象的组合
1 设计线程安全的类原创 2017-09-28 18:35:09 · 1221 阅读 · 0 评论 -
Fork-Join框架
在JDK1.7引入了一种新的并行编程模式“fork-join”,它是实现了“分而治之”思想的Java并发编程框架。网上关于此框架的各种介绍很多,本文从框架特点出发,通过几个例子来进行实用性的介绍。1 fork-join框架的特点fork-join框架对新手来说很难理解,因此先从它的特点说起,它有几个特点: 它对问题的解决思路是分而治之,先将一个问题fork(分为)几个子问题,然后子问题又分为孙子问原创 2017-08-19 22:26:50 · 1363 阅读 · 2 评论 -
Executor框架
在Java中,使用线程来异步执行任务。Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源。同时,为每一个任务创建一个新线程来执行,这种策略可能会使处于高负荷状态的应用最终崩溃。Java的线程既是工作单元,也是执行机制。从JDK 5开始,把工作单元与执行机制分离开来。工作单元包括Runnable和Callable,而执行机制由Ex原创 2017-05-21 10:42:50 · 1154 阅读 · 0 评论