Java并发编程实战
王宝令
资深架构师
立即订阅
15151 人已学习
课程目录
已完结 50 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 你为什么需要学习并发编程?
免费
学习攻略 (1讲)
学习攻略 | 如何才能学好并发编程?
第一部分:并发理论基础 (13讲)
01 | 可见性、原子性和有序性问题:并发编程Bug的源头
02 | Java内存模型:看Java如何解决可见性和有序性问题
03 | 互斥锁(上):解决原子性问题
04 | 互斥锁(下):如何用一把锁保护多个资源?
05 | 一不小心就死锁了,怎么办?
06 | 用“等待-通知”机制优化循环等待
07 | 安全性、活跃性以及性能问题
08 | 管程:并发编程的万能钥匙
09 | Java线程(上):Java线程的生命周期
10 | Java线程(中):创建多少线程才是合适的?
11 | Java线程(下):为什么局部变量是线程安全的?
12 | 如何用面向对象思想写好并发程序?
13 | 理论基础模块热点问题答疑
第二部分:并发工具类 (14讲)
14 | Lock和Condition(上):隐藏在并发包中的管程
15 | Lock和Condition(下):Dubbo如何用管程实现异步转同步?
16 | Semaphore:如何快速实现一个限流器?
17 | ReadWriteLock:如何快速实现一个完备的缓存?
18 | StampedLock:有没有比读写锁更快的锁?
19 | CountDownLatch和CyclicBarrier:如何让多线程步调一致?
20 | 并发容器:都有哪些“坑”需要我们填?
21 | 原子类:无锁工具类的典范
22 | Executor与线程池:如何创建正确的线程池?
23 | Future:如何用多线程实现最优的“烧水泡茶”程序?
24 | CompletableFuture:异步编程没那么难
25 | CompletionService:如何批量执行异步任务?
26 | Fork/Join:单机版的MapReduce
27 | 并发工具类模块热点问题答疑
第三部分:并发设计模式 (10讲)
28 | Immutability模式:如何利用不变性解决并发问题?
29 | Copy-on-Write模式:不是延时策略的COW
30 | 线程本地存储模式:没有共享,就没有伤害
31 | Guarded Suspension模式:等待唤醒机制的规范实现
32 | Balking模式:再谈线程安全的单例模式
33 | Thread-Per-Message模式:最简单实用的分工方法
34 | Worker Thread模式:如何避免重复创建线程?
35 | 两阶段终止模式:如何优雅地终止线程?
36 | 生产者-消费者模式:用流水线思想提高效率
37 | 设计模式模块热点问题答疑
第四部分:案例分析 (4讲)
38 | 案例分析(一):高性能限流器Guava RateLimiter
39 | 案例分析(二):高性能网络应用框架Netty
40 | 案例分析(三):高性能队列Disruptor
41 | 案例分析(四):高性能数据库连接池HiKariCP
第五部分:其他并发模型 (4讲)
42 | Actor模型:面向对象原生的并发模型
43 | 软件事务内存:借鉴数据库的并发经验
44 | 协程:更轻量级的线程
45 | CSP模型:Golang的主力队员
结束语 (1讲)
结束语 | 十年之后,初心依旧
用户故事 (2讲)
用户来信 | 真好,面试考到这些并发编程,我都答对了!
3 个用户来信 | 打开一个新的并发世界
Java并发编程实战
登录|注册

学习攻略 | 如何才能学好并发编程?

王宝令 2019-02-26
并发编程并不是一门相对独立的学科,而是一个综合学科。并发编程相关的概念和技术看上非常零散,相关度也很低,总给你一种这样的感觉:我已经学习很多相关技术了,可还是搞不定并发编程。那如何才能学习好并发编程呢?
其实很简单,只要你能从两个方面突破一下就可以了。一个是“跳出来,看全景”,另一个是“钻进去,看本质”。

跳出来,看全景

我们先说“跳出来”。你应该也知道,学习最忌讳的就是“盲人摸象”,只看到局部,而没有看到全局。所以,你需要从一个个单一的知识和技术中“跳出来”,高屋建瓴地看并发编程。当然,这首要之事就是你建立起一张全景图
不过,并发编程相关的知识和技术还真是错综复杂,时至今日也还没有一张普遍认可的全景图,也许这正是很多人在并发编程方面难以突破的原因吧。好在经过多年摸爬滚打,我自己已经“勾勒”出了一张全景图,不一定科学,但是在某种程度上我想它还是可以指导你学好并发编程的。
在我看来,并发编程领域可以抽象成三个核心问题:分工、同步和互斥

1. 分工

所谓分工,类似于现实中一个组织完成一个项目,项目经理要拆分任务,安排合适的成员去完成。
在并发编程领域,你就是项目经理,线程就是项目组成员。任务分解和分工对于项目成败非常关键,不过在并发领域里,分工更重要,它直接决定了并发程序的性能。在现实世界里,分工是很复杂的,著名数学家华罗庚曾用“烧水泡茶”的例子通俗地讲解了统筹方法(一种安排工作进程的数学方法),“烧水泡茶”这么简单的事情都这么多说道,更何况是并发编程里的工程问题呢。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java并发编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(85)

  • 常江舟
    从性能角度讲,我们为了提高执行一定计算机任务的效率,所以IO等待的时候不能让cpu闲着,所以我们把任务拆分交替执行,有了分时操作系统,出现了并发,后来cpu多核了又有了并行计算。这里也就是作者说的[分工]。分工以后我们为了进一步提升效率和更加灵活地达到目的,所以我们要对任务进行组织编排,也就是对线程组织编排。于是线程之间需要通信,于是操作系统提供了一些让进程,线程之间通信的方式。也就是作者说的[同步]。但是事物总不是完美的。并发和通信带来了较高的编程复杂度,同时也出现了多线程并发操作共享资源的问题。于是天下大势,分久必合,我们又要将对共享资源的访问串行化。所以我们根据现实世界的做法设计了了锁,信号量等等来补充这套体系。也就是作者所说的[互斥]!

    综上,这一切均为提高性能的手段和对其所产生问题的解决方案。

    作者回复: 正解

    2019-02-26
    199
  • Jerry银银
    这篇文章看了四五篇,写得真好,收获也很多。
          文中提到了两点真是发人深省:
          1. 方法论层面:「跳出来,看全景」 和 「钻进去,看本质」,这两条方法论,我想是适合很多领域的学习的。
          2. 并发领域的「全景图」。
          对于「全景图」,我之前也有一直在构建,可是因为知识储备不够,确实很难构建出来。稍微了解过并发领域知识的人都知道,里面的知识点、概念多而散:线程安全、锁、同步、异步、阻塞、非阻塞、死锁、队列(为什么并发要跟队列扯上关系)、闭锁、信号量、活锁等等。如果单个去学这些知识点,单个去练习,如果没有「主线」,后期很容易忘。我思考再思考,也总结了一下学习并发的主线:
          首先,得理解并发的重要性,为什么需要并发?对于这个问题,只需要放在潜意识里面,只需要两个字:性能!其它的细节,再去慢慢拓展。
          然后,既然并发很重要,而并发处理的是任务,接下就是:对任务的抽象、拆解、分工执行。而线程模型,只是其中的一种模型,还有多进程、协程。Java使用的是多线程模型,对应到具体的代码就是:Thread, Runnable, Task,执行任务有:Exectors。 引出了线程,有势必存在着线程安全性的问题,因为多线程访问,数据存在着不一致的问题。
          再然后,大的任务被拆解多个小的子任务,小的子任务被各自执行,不难想象,子任务之间肯定存在着依赖关系,所以需要协调,那如何协调呢?也不难想到,锁是非常直接的方式(Monitor原理),但是只用锁,协调的费力度太高,在并发的世界里面,又有了一些其它的更抽象的工具:闭锁、屏障、队列以及其它的一些并发容器等;好了,协调的工作不难处理了。可是协调也会有出错的时候,这就有了死锁、活锁等问题,大师围绕着这个问题继续优化协调工具,尽量让使用者不容易出现这些活跃性问题;
          到此,「并发」的历史还在演化:如果一遇到并发问题,就直接上锁,倒也没有什么大问题,可是追求性能是人类的天性。计算机大师就在思考,能不不加锁也能实现并发,还不容易出错,于是就有了:CAS、copy-on-write等技术思想,这就是实现了「无锁」并发;
          可是,事情到此还没有完。如果以上这些个东西,都需要每个程序员自己去弄,然后自己保证正确性,那程序员真累死了,哪还有时间、精力创造这么多美好的应用!于是,计算机大师又开始思考,能不能抽象出统一「模型」,可能这就有了类似于「Java内存模型」这样的东西。
    ------------
    借用宝令老师的语言,以上「是我对并发问题的个人总结,不一定正确,但是可以帮助我快速建立解决并发问题的思路,梳理并发编程的知识,加深认识。我将其分享给你,希望对你也有用」。

    作者回复: 我觉得你比我总结的好👍

    2019-03-06
    1
    115
  • Minecraft
    并发编程学习 第一天 明天去面试 祝我好运
    2019-02-26
    1
    76
  • Jerry银银
    之前看薛兆丰的《经济学通识》,他总结到,人类面临着四大基本约束:东西不够,生命有限,互相依赖,需要协调。当我看到这句话的时候,我猛然间意识到:计算机也同样面临着这四大基本约束。

    在计算中,CPU、内存、IO、硬盘、带宽等,这些资源也都有不够的时候,而每个线程的也有着自己的生命周期,并且它们之间又是相互依赖的,也同样需要协调。

    有了上面的这种想法,我觉得我学习计算机的知识有了章法可循。

    作者回复: 好厉害

    2019-03-06
    3
    67
  • crazypokerk
    感觉确实如老师所说的,知识不成体系,就像是奶酪,看着是一块,实则满眼孔洞,加油!

    作者回复: 这个比喻我是服了

    2019-02-26
    32
  • 令哥,你就坐我对面,让我如何评论啊!呵呵

    作者回复: 使劲夸就行了,我不介意

    2019-02-26
    27
  • 墙角
    正如老师所说,并发编程涉及的知识面比较广,无奈大学阶段没有学好,老师帮忙推荐下和并发编程相关的书籍。只有有了一定的知识铺垫,才能更好的理解并发编程。感谢!

    作者回复: 《Java并发编程实战》作者阵容可谓大师云集,也包括Doug Lea
    《Java并发编程的艺术》讲解并发包内部实现原理,能读明白,内功大增
    《图解Java多线程设计模式》并发编程设计模式方面的经典书籍
    《操作系统:精髓与设计原理》经典操作系统教材
    http://ifeve.com 国内专业并发编程网站
    http://www.cs.umd.edu/~pugh/java/memoryModel/ 很多并发编程的早期资料都在这里

    2019-03-06
    24
  • Handongyang
    想给老师提一个建议,就是在开篇用一个问题来引出本篇所要讲述的内容,然后在结尾时的总结之前回答开篇的问题。最后,在总结之后再设计并提出一个问题,让大家来讨论和回答。每一课之后的激烈讨论将是最有意思的,望老师考虑一下,谢谢!

    作者回复: 你的建议非常好,我努力向这个方向前进

    2019-02-26
    22
  • 我会得到
    全局思维加单点突破,这种方式屡试不爽。希望令哥沉住气不着急,好好打磨,慢慢更新,搞出精品,打造业界标杆😁

    作者回复: 借你吉言

    2019-02-26
    21
  • minggushen
    老师想请教您一个问题,目前公司需要进行分表操作,单表2亿数据,每年的增量也是两亿。有没有什么理论基础支持我分片的片数,以及是否需要分库以及其他注意事项。如果没有的话,老师按照您的经验,应该分成多少个片呢?目前是用的哈希对128取模进行的,分成128个表,是否合适呢。

    作者回复: 建议先做个冷热分离吧,如果不能做,建议分库,分片规则很重要,要结合业务,具体问题具体分析。回头我再出个分布式计算的专栏......

    2019-02-26
    1
    11
  • 梅云霞
    总结

    当初我学习 Java 并发编程的时候,试图上来就看 Java SDK 的并发包,但是很快就放弃了。原因是我觉得东西太多,眼花缭乱的,虽然借助网络上的技术文章,感觉都看懂了,但是很快就又忘了。实际应用的时候大脑也一片空白,根本不知道从哪里下手,有时候好不容易解决了个问题,也不知道这个方案是不是合适的。
    说出了我的处境!如何记住Java SDK 的并发包就像记住ABC呢

    作者回复: 买个专栏啊

    2019-02-26
    8
  • 王二宝
    我和老师的观念是一样的,如果碰到自己一直搞不定的问题时,我的应对方法也是:从两个方面突破。一个是“跳出来,看全景”,另一个是“钻进去,看本质”。

    作者回复: 同感

    2019-02-26
    8
  • 个人一点建议因大家基础功底不一且并发知识面广,若专栏篇幅受限的话,还望讲的过程中给出一些相关链接知识,方便理解,望采纳!

    作者回复: 多谢建议,必须采纳!

    2019-03-01
    7
  • Joker
    这是我在极客学院购买的第一份产品,也是因为纯洁的微笑才买的这份产品,希望自己能坚持下去,在并发编程这方面有点突破

    编辑回复: 极客时间,哥哥

    2019-02-28
    1
    6
  • 邋遢的流浪剑客
    过年的时候看了一遍java并发编程的艺术,感觉有点晕,正好跟着老师的课在深入理解一下

    作者回复: 那本书属于高段位的,适合学完这个专栏后再看

    2019-02-26
    6
  • 发条橙子 。
    总结 :

    并发编程需要构造出一个全景图 。 只要分为三大点 : 分工、协作、互斥。

    先将一个大的逻辑按不同的工作去分配给不同的线程 , 这些线程可以同时进行 ,也可以一个线程结束后再进行下一个进程,这时就需要线程间的协作 , 最后如果是多个线程同时进行并且会访问同一个共享资源时就需要对这个资源加锁以便造成资源的不一致 ,这就是互斥

    当全景图有了就需要深入到各个点, java sdk 的并发包中提供了很多工具帮我们处理上面三大点, 比如分工的fork/join 、协作的 future 、 互斥的各种锁以及无锁原子类等 。

    这只是表面 , 我们更要深入其中了解其背后的理论,比如很多 sdk并发包中的工具都是基于管程的思想 。 了解了这个思想才能举一反三 ,站在更高的视野去理解并发的本质

    另外,希望老师也可以着重讲一些管程这类的原理概念,我也是第一次听到这个词甚是感兴趣 , 并且老师说道并发的处理大多涉及操作系统相关的知识,也希望老师能推荐一些书籍或者文章资料便于我们更深入的理解学习

    作者回复: 专栏有专门一期讲管程,每一期都会有相关推荐

    2019-02-26
    4
  • 木易走刀口
    好东西值得认真学习

    作者回复: 感谢杨总支持!

    2019-02-26
    3
  • balance
    并发编程全景图总结:出发点是为了提高【性能】,为了提高性能就得【分工】,分工做事就需要协做,协做即【同步】,在分工协做的同时,存在同时对共享资源的占用、操作的问题,那就带来了共享资源【安全】的问题,解决安全问题的方法就【互斥】。性能是要解决的问题,安全是引出的问题。为什么同时对共享资源的操作会有安全性问题,主要是因为【可见性】、【原子性】、【有序性】问题导致。
    2019-09-20
    2
  • 拯救地球好累
    再谈如何学习并发编程?
        1. 高屋建瓴,整体架构->可以画出思维导图
        2. 深入本质,直抓核心->理论需要追根溯源,这里的源追到哪儿,对并发编程而言,我觉得到数据结构与算法、操作系统这一层面就足够了

    谈谈自己对分工、同步、互斥的理解?
    分工。分工其实有两个阶段,一是如何将一个大任务划分成多个小任务,二是如何将多个小任务交给多个线程去协作完成。前者老师称为任务分解,是我们在业务层面需要考虑的问题,有些问题是易于拆分的,如数组求和等,而有些问题的拆分却很难,是否利于拆分非常依赖于问题本身的复杂性和业务模型的设计好坏。后者则是一些并发包里为我们提供的一些分工方法和设计模式中为我们提供的指导法则。
    从操作系统的线程模型看分工:以Linux为例,其将线程分为用户级线程、轻量级进程、内核级线程三种,用户级线程处理用户态下的基本任务,而当中断等行为发生时,需要切换到内核态,由内核级线程执行中断服务程序。
    分工的实例:Executor,Frok/Join,Feture,各种并发设计模式等
    同步。同步是指线程间的协作。线程可以自己独立完成一些子任务,但在完成子任务的过程中或者完成后需要与其他线程交互协作,比如在线程完成一个子任务后需要返回结果给主线程、在子任务完成过程中可能与其他线程有依赖关系,需要等待其他线程某个信号的通知等。
    同步的实例:Semaphore,Monitor,CountDownLatch等
    互斥。互斥是并发程序对共享变量的保护措施,已达到线程安全的目的。导致共享变量不确定性的核心三大问题是可见性、有序性、原子性问题,而互斥则是解决这些问题的一种较强硬的手段---同一时刻,只有一个线程访问共享变量。
    互斥的实例:互斥锁和无锁等

    启发:
        1. 老师的这种既抓全局又抓原理核心的方式十分有收获,并且尝试自己归纳总结整体概念,《程序员的思维修炼》中曾谈到,我们的学习过程需要右脑思维和左脑思维的结合,右脑看森林,左脑看树木,这也是一种系统化的学习方式,希望在之后学习每一项新技术时都能做到这两点。
        2. 同学们对三个概念的理解从追根溯源地从CPU、内存、硬盘等角度思考为什么,很有启发

    作者回复: 👍👍总结的真好

    2019-07-16
    2
  • 遠い道の先で
    1、跳出来看全景,钻进去看本质。
    -在进入一个新领域学习时,建立一张学习线路的全景图,由点成线由线成面,贯穿整个学习过程。
    -在学到某个具体问题时,钻进去看本质,了解技术背后的理论模型,了解当初这个理论产生的环境时什么,主要解决什么问题。
    2、一些重要的知识前任一定有所研究并有相应的结果,可以先查阅目前最可靠的解决方案,提高自己的基线。
    3、分工:将一个大的任务(项目)拆分成若干个小任务,并安排适合的成员去执行。
    4、同步:每个小任务间可能存在相互依赖,同步需要做的是在前置任务完成后,通知后置任务启动。
    5、互斥:互斥主要解决正确性问题。互斥要求同一时间,只允许一个线程访问共享变量。
    6、管程monitor是解决并非问题的万?能?钥匙。(这个完全不理解)
    7、一项优秀的理论往往在多个语言中都有体现,学习过程中应注重理论的学习。
    —————
    以上是听课过程中的笔记,下面说说自己的感悟:
            之前听过吴军老师的课程,讲到民间科学家为何难以作出成绩,是因为基线不高。老师在课中有讲到我们可以通过学习优秀前辈研究和成果去学习并发编程。非常同意两位老师的观点。
            跳出来看全景,钻进去看本质。这个观点很新颖我也非常认同,在日常的碎片化学习往往会让我们这学一点那些一点,感觉好像学了很多,但又感觉不知道学习什么。
            在学习前制定一张学习地图,就像一棵树先有树干再有树枝,会成长的枝繁叶茂的。
            平时遇到一个新的知识,我们可能一开始只知道怎么用,没有去探究它的本质,可能导致最终我们只会基础的使用而没有办法举一反三,下次遇到了还是新问题。
            这是第一次在极客时间购买课程,希望自己能跟上每一堂课,和大家一起成长。

    作者回复: 眼光不错哈哈

    2019-03-13
    2
收起评论
85
返回
顶部