![](https://img-blog.csdnimg.cn/20201014180756724.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
并发编程
大神,快来碗里
专注于Java相关技术
展开
-
并发编程 (20)并发容器:都有哪些“坑”需要我们填?
ava 并发包有很大一部分内容都是关于并发容器的,因此学习和搞懂这部分的内容很有必要。Java 1.5 之前提供的同步容器虽然也能保证线程安全,但是性能很差,而 Java 1.5 版本之后提供的并发容器在性能方面则做了很多优化,并且容器的类型也更加丰富了。下面我们就对比二者来学习这部分的内容。同步容器及其注意事项Java 中的容器主要可以分为四个大类,分别是 List、Map、Set 和 Q...原创 2019-12-09 21:44:02 · 786 阅读 · 0 评论 -
并发编程 (19)CountDownLatch和CyclicBarrier:如何让多线程步调一致?
前几天老板突然匆匆忙忙过来,说对账系统最近越来越慢了,能不能快速优化一下。我了解了对账系统的业务后,发现还是挺简单的,用户通过在线商城下单,会生成电子订单,保存在订单库;之后物流会生成派送单给用户发货,派送单保存在派送单库。为了防止漏派送或者重复派送,对账系统每天还会校验是否存在异常订单。对账系统的处理逻辑很简单,你可以参考下面的对账系统流程图。目前对账系统的处理逻辑是首先查询订单,然后查询派送...原创 2019-12-09 21:32:59 · 346 阅读 · 0 评论 -
并发编程 (18)StampedLock:有没有比读写锁更快的锁?
我们介绍了读写锁,学习完之后你应该已经知道“读写锁允许多个线程同时读共享变量,适用于读多写少的场景”。那在读多写少的场景中,还有没有更快的技术方案呢?还真有,Java 在 1.8 这个版本里,提供了一种叫 StampedLock 的锁,它的性能就比读写锁还要好。下面我们就来介绍一下 StampedLock 的使用方法、内部工作原理以及在使用过程中需要注意的事项。StampedLock 支持的三...原创 2019-12-09 21:24:10 · 392 阅读 · 0 评论 -
并发编程 (17)ReadWriteLock:如何快速实现一个完备的缓存?
前面我们介绍了管程和信号量这两个同步原语在 Java 语言中的实现,理论上用这两个同步原语中任何一个都可以解决所有的并发问题。那 Java SDK 并发包里为什么还有很多其他的工具类呢?原因很简单:分场景优化性能,提升易用性。今天我们就介绍一种非常普遍的并发场景:读多写少场景。实际工作中,为了优化性能,我们经常会使用缓存,例如缓存元数据、缓存基础数据等,这就是一种典型的读多写少应用场景。缓存之所...原创 2019-12-09 21:19:53 · 247 阅读 · 0 评论 -
并发编程 (16)Semaphore:如何快速实现一个限流器
Semaphore,现在普遍翻译为“信号量”,以前也曾被翻译成“信号灯”,因为类似现实生活里的红绿灯,车辆能不能通行,要看是不是绿灯。同样,在编程世界里,线程能不能执行,也要看信号量是不是允许。信号量是由大名鼎鼎的计算机科学家迪杰斯特拉(Dijkstra)于 1965 年提出,在这之后的 15 年,信号量一直都是并发编程领域的终结者,直到 1980 年管程被提出来,我们才有了第二选择。目前几乎所...原创 2019-12-09 21:16:24 · 724 阅读 · 0 评论 -
并发编程 (15)Lock和Condition(下):Dubbo如何用管程实现异步转同步?
在上一篇文章中,我们讲到 Java SDK 并发包里的 Lock 有别于 synchronized 隐式锁的三个特性:能够响应中断、支持超时和非阻塞地获取锁。那今天我们接着再来详细聊聊 Java SDK 并发包里的 Condition,Condition 实现了管程模型里面的条件变量。在《并发编程(9)管程:并发编程的万能钥匙》里我们提到过 Java 语言内置的管程里只有一个条件变量,而 Loc...原创 2019-12-08 12:57:05 · 12020 阅读 · 0 评论 -
并发编程 (14)Lock和Condition(上):隐藏在并发包中的管程
Java SDK 并发包内容很丰富,包罗万象,但是我觉得最核心的还是其对管程的实现。因为理论上利用管程,你几乎可以实现并发包里所有的工具类。在前面《并发编程(9)管程:并发编程的万能钥匙》中我们提到过在并发编程领域,有两大核心问题:一个是互斥,即同一时刻只允许一个线程访问共享资源;另一个是同步,即线程之间如何通信、协作。这两大问题,管程都是能够解决的。Java SDK 并发包通过 Lock 和 C...原创 2019-12-08 12:17:10 · 11173 阅读 · 0 评论 -
并发编程(13)如何用面向对象思想写好并发程序
在工作中,我发现很多同学在设计之初都是直接按照单线程的思路来写程序的,而忽略了本应该重视的并发问题;等上线后的某天,突然发现诡异的 Bug,再历经千辛万苦终于定位到问题所在,却发现对于如何解决已经没有了思路。关于这个问题,我觉得咱们今天很有必要好好聊聊“如何用面向对象思想写好并发程序”这个话题。面向对象思想与并发编程有关系吗?本来是没关系的,它们分属两个不同的领域,但是在 Java 语言里,这...原创 2019-12-08 11:31:06 · 11998 阅读 · 0 评论 -
并发编程 (12) Java线程(下):为什么局部变量是线程安全的?
我们一遍一遍重复再重复地讲到,多个线程同时访问共享变量的时候,会导致并发问题。那在 Java 语言里,是不是所有变量都是共享变量呢?工作中我发现不少同学会给方法里面的局部变量设置同步,显然这些同学并没有把共享变量搞清楚。那 Java 方法里面的局部变量是否存在并发问题呢?下面我们就先结合一个例子剖析下这个问题。比如,下面代码里的 fibonacci() 这个方法,会根据传入的参数 n ,返回 1...原创 2019-12-08 11:22:22 · 10794 阅读 · 1 评论 -
并发编程(11)Java线程(中):创建多少线程才是合适的?
要解决这个问题,首先要分析以下两个问题:为什么要使用多线程?多线程的应用场景有哪些?为什么要使用多线程?使用多线程,本质上就是提升程序性能。不过此刻谈到的性能,可能在你脑海里还是比较笼统的,基本上就是快、快、快,这种无法度量的感性认识很不科学,所以在提升性能之前,首要问题是:如何度量性能。度量性能的指标有很多,但是有两个指标是最核心的,它们就是延迟和吞吐量。延迟指的是发出请求到收到响...原创 2019-12-08 11:10:24 · 12464 阅读 · 0 评论 -
并发编程 (10)Java线程(上):Java线程的生命周期
通用的线程生命周期通用的线程生命周期基本上可以用下图这个“五态模型”来描述。这五态分别是:初始状态、可运行状态、运行状态、休眠状态和终止状态。这“五态模型”的详细情况如下所示。初始状态,指的是线程已经被创建,但是还不允许分配 CPU 执行。这个状态属于编程语言特有的,不过这里所谓的被创建,仅仅是在编程语言层面被创建,而在操作系统层面,真正的线程还没有创建。可运行状态,指的是线程可以分配...原创 2019-12-07 23:13:00 · 10990 阅读 · 0 评论 -
并发编程(9)管程:并发编程的万能钥匙
什么是管程不知道你是否曾思考过这个问题:为什么 Java 在 1.5 之前仅仅提供了 synchronized 关键字及 wait()、notify()、notifyAll() 这三个看似从天而降的方法?在刚接触 Java 的时候,我以为它会提供信号量这种编程原语,因为操作系统原理课程告诉我,用信号量能解决所有并发问题,结果我发现不是。后来我找到了原因:Java 采用的是管程技术,synchro...原创 2019-12-07 23:05:41 · 10773 阅读 · 0 评论 -
并发编程 (8)安全性、活跃性以及性能问题
通过前面六篇文章,我们开启了一个简单的并发旅程,相信现在你对并发编程需要注意的问题已经有了更深入的理解,这是一个很大的进步,正所谓只有发现问题,才能解决问题。但是前面六篇文章的知识点可能还是有点分散,所以是时候将其总结一下了。并发编程中我们需要注意的问题有很多,很庆幸前人已经帮我们总结过了,主要有三个方面,分别是:安全性问题、活跃性问题和性能问题。下面我就来一一介绍这些问题。安全性问题相信你...原创 2019-12-07 22:47:41 · 10767 阅读 · 0 评论 -
并发编程 (7)用“等待-通知”机制优化循环等待
由上一篇文章你应该已经知道,在破坏占用且等待条件的时候,如果转出账本和转入账本不满足同时在文件架上这个条件,就用死循环的方式来循环等待,核心代码如下:// 一次性申请转出账户和转入账户,直到成功while(!actr.apply(this, target)) ;如果 apply() 操作耗时非常短,而且并发冲突量也不大时,这个方案还挺不错的,因为这种场景下,循环上几次或者几十次就能一次...原创 2019-12-07 22:32:01 · 10693 阅读 · 0 评论 -
并发编程 (6)一不小心就死锁了,怎么办?
在上一篇文章中,我们用 Account.class 作为互斥锁,来解决银行业务里面的转账问题,虽然这个方案不存在并发问题,但是所有账户的转账操作都是串行的,例如账户 A 转账户 B、账户 C 转账户 D 这两个转账操作现实世界里是可以并行的,但是在这个方案里却被串行化了,这样的话,性能太差。试想互联网支付盛行的当下,8 亿网民每人每天一笔交易,每天就是 8 亿笔交易;每笔交易都对应着一次转账操作...原创 2019-12-07 22:21:34 · 10387 阅读 · 0 评论 -
并发编程 (5)互斥锁(下):如何用一把锁保护多个资源?
在上一篇文章中,我们提到受保护资源和锁之间合理的关联关系应该是 N:1 的关系,也就是说可以用一把锁来保护多个资源,但是不能用多把锁来保护一个资源,并且结合文中示例,我们也重点强调了“不能用多把锁来保护一个资源”这个问题。而至于如何保护多个资源,我们今天就来聊聊。保护没有关联关系的多个资源在现实世界里,球场的座位和电影院的座位就是没有关联关系的,这种场景非常容易解决,那就是球赛有球赛的门票,电...原创 2019-12-07 22:14:29 · 11873 阅读 · 0 评论 -
并发编程 (4)互斥锁(上):解决原子性问题
那原子性问题到底该如何解决呢?你已经知道,原子性问题的源头是线程切换,如果能够禁用线程切换那不就能解决这个问题了吗?而操作系统做线程切换是依赖 CPU 中断的,所以禁止 CPU 发生中断就能够禁止线程切换。在早期单核 CPU 时代,这个方案的确是可行的,而且也有很多应用案例,但是并不适合多核场景。这里我们以 32 位 CPU 上执行 long 型变量的写操作为例来说明这个问题,long 型变量...原创 2019-12-07 21:59:20 · 11619 阅读 · 0 评论 -
并发编程 (3)Java内存模型:看Java如何解决可见性和有序性问题
什么是 Java 内存模型?你已经知道,导致可见性的原因是缓存,导致有序性的原因是编译优化,那解决可见性、有序性最直接的办法就是禁用缓存和编译优化,但是这样问题虽然解决了,我们程序的性能可就堪忧了。合理的方案应该是按需禁用缓存以及编译优化。那么,如何做到“按需禁用”呢?对于并发程序,何时禁用缓存以及编译优化只有程序员知道,那所谓“按需禁用”其实就是指按照程序员的要求来禁用。所以,为了解决可见性...原创 2019-12-07 21:21:50 · 11096 阅读 · 0 评论 -
并发编程(2)可见性、原子性和有序性问题:并发编程Bug的源头
并发程序幕后的故事这些年,我们的 CPU、内存、I/O 设备都在不断迭代,不断朝着更快的方向努力。但是,在这个快速发展的过程中,有一个核心矛盾一直存在,就是这三者的速度差异。CPU 和内存的速度差异可以形象地描述为:CPU 是天上一天,内存是地上一年(假设 CPU 执行一条普通指令需要一天,那么 CPU 读写内存得等待一年的时间)。内存和 I/O 设备的速度差异就更大了,内存是天上一天,I/O ...原创 2019-12-07 21:03:21 · 10753 阅读 · 0 评论 -
并发编程(1)学习攻略如何才能学好并发编程?
并发编程并不是一门相对独立的学科,而是一个综合学科。并发编程相关的概念和技术看上非常零散,相关度也很低,总给你一种这样的感觉:我已经学习很多相关技术了,可还是搞不定并发编程。那如何才能学习好并发编程呢?其实很简单,只要你能从两个方面突破一下就可以了。一个是“跳出来,看全景”,另一个是“钻进去,看本质”。跳出来,看全景我们先说“跳出来”。你应该也知道,学习最忌讳的就是“盲人摸象”,只看到局部,...原创 2019-12-07 20:46:17 · 12685 阅读 · 1 评论