Java 并发编程实战
王宝令
资深架构师
72485 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
学习攻略 (1讲)
Java 并发编程实战
15
15
1.0x
00:00/00:00
登录|注册

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

StampedLock
ReadWriteLock
Lock
synchronized
Worker Thread
Thread-Per-Message
生产者-消费者
其他方案
无锁数据结构
Exchanger
Phaser
CyclicBarrier
CountDownLatch
Future
设计模式
Future
Fork/Join
Executor
死锁问题
互斥方法
线程安全
管程
协作方法
线程协作
任务依赖
分工方法
任务分解与分工
项目经理与线程
探索背后的理论
理论基础
互斥
同步
分工
建立全景图
探索技术背后的理论本质
分工、同步和互斥的全景图
挖掘Java SDK并发包背后的设计理念
知识成体系
钻进去,看本质
跳出来,看全景
总结
如何学好并发编程?

该思维导图由 AI 生成,仅供参考

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

跳出来,看全景

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

1. 分工

所谓分工,类似于现实中一个组织完成一个项目,项目经理要拆分任务,安排合适的成员去完成。
在并发编程领域,你就是项目经理,线程就是项目组成员。任务分解和分工对于项目成败非常关键,不过在并发领域里,分工更重要,它直接决定了并发程序的性能。在现实世界里,分工是很复杂的,著名数学家华罗庚曾用“烧水泡茶”的例子通俗地讲解了统筹方法(一种安排工作进程的数学方法),“烧水泡茶”这么简单的事情都这么多说道,更何况是并发编程里的工程问题呢。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

学习并发编程需要从全景和本质两个方面着手。全景包括分工、同步和互斥三个核心问题,涉及任务拆分、线程分配、线程间协作和线程安全等方面。通过学习设计模式、Java SDK中的Executor、Fork/Join、Future等工具类,以及CountDownLatch、CyclicBarrier、Phaser等工具类,可以加深对并发编程的理解。同时,需要关注并发编程背后的理论模型,探索技术的本质,以建立知识体系,融会贯通。挖掘Java SDK并发包背后的设计理念,可以帮助快速建立解决并发问题的思路,梳理并发编程的知识,加深认识。探索技术背后的理论本质,不仅能加深对技术本身的理解,也能拓展知识深度和广度。因此,建议探求理论本质,共同进步。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(122)

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

    作者回复: 正解

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

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

    2019-03-06
    8
    369
  • Jerry银银
    之前看薛兆丰的《经济学通识》,他总结到,人类面临着四大基本约束:东西不够,生命有限,互相依赖,需要协调。当我看到这句话的时候,我猛然间意识到:计算机也同样面临着这四大基本约束。 在计算中,CPU、内存、IO、硬盘、带宽等,这些资源也都有不够的时候,而每个线程的也有着自己的生命周期,并且它们之间又是相互依赖的,也同样需要协调。 有了上面的这种想法,我觉得我学习计算机的知识有了章法可循。

    作者回复: 好厉害

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

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

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

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

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

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

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

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

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

    作者回复: 借你吉言

    2019-02-26
    30
  • 雷刚
    理论确实特别重要。我在数据结构与算法这门课程中,学习到了跳表这种数据结构时,又重新读了一下 JUC 中 ConcurrentSkipListMap,感触颇深。 在学习跳表过程中,我了解了跳表的基本数据结构。数组的二分法查找二分高效,时间复杂度为 O(logn),但直接使用链表进行二分法查找却十分低效。为了解决这个问题,跳表通过存储多级索引(类似多级链表),实现了基于链表的二分法查找。如何创建跳表,这些问题其实在 William Pugh 的《[Skip Lists: A Probabilistic Alternative to Balanced Trees](ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf)》一文中分析的特别清楚。影响跳表的性能关键就是索引的平衡,跳表通过随机函数生成索引高度。其中有两个最关键的指标:每层指针的概率 p(决定每个结点的平均索引高度)和最大索引高度 MaxLevel(决定了跳表的最大索引高度和最大数据量 2^MaxLevel)。所以我重新读 ConcurrentSkipListMap 时就重点关注一下它的这两个指标p=0.5且MaxLevel=32。这样跳表的结构就非常的清晰了,其它的都是一些细枝末节。 ConcurrentSkipListMap 的数据结构基本上没问题,但链表中大量的原子性操作又成了拦路虎,刚开始完全搞不明白。然后,我又硬着头皮读了一下 Doug Lea 的 Javadoc,其中提到了 Tim Harris 的《A pragmatic implementation of non-blocking linked lists》论文,讲述了如何实现无锁的链表。但这篇论文太难找了,最后我找到了一遍简要介绍 TH 的文章。文章大致说的是,多线程下通过 cas 往链表中插入结点是安全的。但通过 cas 删除结点却是不安全的,因为在删除结点时,有可能其它线程正在往这个将要被删除的结点后插入元素。解决问题的办法也很简单,将被删除的结点先逻辑删除,再物理删除,也就标记删除法。有了这些理论基础,再读并发部分的代码就觉得很清晰多了,ConcurrentSkipListMap 也是通过先标记后删除解决这个问题的。一旦将node.value设置为null,结点就不可达,但还可以往这个结点后插入元素,所以将node.value设置为null后,还需要node.next设置成标记位,这样就不能再插入元素了,这个结点也就可以真正从链表中删除了。本来以为自己分析还比较到位,结果我发现在《Java多线程编程核心技术》这本书中,对无锁链表的总结真是面面俱到,只能怪自己这方面的理论欠缺。

    作者回复: 先让我膜拜一会儿😄

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

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

    2019-02-26
    4
    22
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部