极客时间已完结课程限时免费阅读

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

学习攻略 | 如何才能学好并发编程?-极客时间

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

讲述:王宝令

时长12:48大小11.71M

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

跳出来,看全景

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

1. 分工

所谓分工,类似于现实中一个组织完成一个项目,项目经理要拆分任务,安排合适的成员去完成。
在并发编程领域,你就是项目经理,线程就是项目组成员。任务分解和分工对于项目成败非常关键,不过在并发领域里,分工更重要,它直接决定了并发程序的性能。在现实世界里,分工是很复杂的,著名数学家华罗庚曾用“烧水泡茶”的例子通俗地讲解了统筹方法(一种安排工作进程的数学方法),“烧水泡茶”这么简单的事情都这么多说道,更何况是并发编程里的工程问题呢。
既然分工很重要又很复杂,那一定有前辈努力尝试解决过,并且也一定有成果。的确,在并发编程领域这方面的成果还是很丰硕的。Java SDK 并发包里的 Executor、Fork/Join、Future 本质上都是一种分工方法。除此之外,并发编程领域还总结了一些设计模式,基本上都是和分工方法相关的,例如生产者 - 消费者、Thread-Per-Message、Worker Thread 模式等都是用来指导你如何分工的。
学习这部分内容,最佳的方式就是和现实世界做对比。例如生产者 - 消费者模式,可以类比一下餐馆里的大厨和服务员,大厨就是生产者,负责做菜,做完放到出菜口,而服务员就是消费者,把做好的菜给你端过来。不过,我们经常会发现,出菜口有时候一下子出了好几个菜,服务员是可以把这一批菜同时端给你的。其实这就是生产者 - 消费者模式的一个优点,生产者一个一个地生产数据,而消费者可以批处理,这样就提高了性能。

2. 同步

分好工之后,就是具体执行了。在项目执行过程中,任务之间是有依赖的,一个任务结束后,依赖它的后续任务就可以开工了,后续工作怎么知道可以开工了呢?这个就是靠沟通协作了,这是一项很重要的工作。
在并发编程领域里的同步,主要指的就是线程间的协作,本质上和现实生活中的协作没区别,不过是一个线程执行完了一个任务,如何通知执行后续任务的线程开工而已。
协作一般是和分工相关的。Java SDK 并发包里的 Executor、Fork/Join、Future 本质上都是分工方法,但同时也能解决线程协作的问题。例如,用 Future 可以发起一个异步调用,当主线程通过 get() 方法取结果时,主线程就会等待,当异步执行的结果返回时,get() 方法就自动返回了。主线程和异步线程之间的协作,Future 工具类已经帮我们解决了。除此之外,Java SDK 里提供的 CountDownLatch、CyclicBarrier、Phaser、Exchanger 也都是用来解决线程协作问题的。
不过还有很多场景,是需要你自己来处理线程之间的协作的。
工作中遇到的线程协作问题,基本上都可以描述为这样的一个问题:当某个条件不满足时,线程需要等待,当某个条件满足时,线程需要被唤醒执行。例如,在生产者 - 消费者模型里,也有类似的描述,“当队列满时,生产者线程等待,当队列不满时,生产者线程需要被唤醒执行;当队列空时,消费者线程等待,当队列不空时,消费者线程需要被唤醒执行。”
在 Java 并发编程领域,解决协作问题的核心技术是管程,上面提到的所有线程协作技术底层都是利用管程解决的。管程是一种解决并发问题的通用模型,除了能解决线程协作问题,还能解决下面我们将要介绍的互斥问题。可以这么说,管程是解决并发问题的万能钥匙
所以说,这部分内容的学习,关键是理解管程模型,学好它就可以解决所有问题。其次是了解 Java SDK 并发包提供的几个线程协作的工具类的应用场景,用好它们可以妥妥地提高你的工作效率。

3. 互斥

分工、同步主要强调的是性能,但并发程序里还有一部分是关于正确性的,用专业术语叫“线程安全”。并发程序里,当多个线程同时访问同一个共享变量的时候,结果是不确定的。不确定,则意味着可能正确,也可能错误,事先是不知道的。而导致不确定的主要源头是可见性问题、有序性问题和原子性问题,为了解决这三个问题,Java 语言引入了内存模型,内存模型提供了一系列的规则,利用这些规则,我们可以避免可见性问题、有序性问题,但是还不足以完全解决线程安全问题。解决线程安全问题的核心方案还是互斥。
所谓互斥,指的是同一时刻,只允许一个线程访问共享变量。
实现互斥的核心技术就是锁,Java 语言里 synchronized、SDK 里的各种 Lock 都能解决互斥问题。虽说锁解决了安全性问题,但同时也带来了性能问题,那如何保证安全性的同时又尽量提高性能呢?可以分场景优化,Java SDK 里提供的 ReadWriteLock、StampedLock 就可以优化读多写少场景下锁的性能。还可以使用无锁的数据结构,例如 Java SDK 里提供的原子类都是基于无锁技术实现的。
除此之外,还有一些其他的方案,原理是不共享变量或者变量只允许读。这方面,Java 提供了 Thread Local 和 final 关键字,还有一种 Copy-on-write 的模式。
使用锁除了要注意性能问题外,还需要注意死锁问题。
这部分内容比较复杂,往往还是跨领域的,例如要理解可见性,就需要了解一些 CPU 和缓存的知识;要理解原子性,就需要理解一些操作系统的知识;很多无锁算法的实现往往也需要理解 CPU 缓存。这部分内容的学习,需要博览群书,在大脑里建立起 CPU、内存、I/O 执行的模拟器。这样遇到问题就能得心应手了。
跳出来,看全景,可以让你的知识成体系,所学知识也融汇贯通起来,由点成线,由线及面,画出自己的知识全景图。
并发编程全景图之思维导图

钻进去,看本质

但是光跳出来还不够,还需要下一步,就是在某个问题上钻进去,深入理解,找到本质。
就拿我个人来说,我已经烦透了去讲述或被讲述一堆概念和结论,而不分析这些概念和结论是怎么来的,以及它们是用来解决什么问题的。在大学里,这样的教材很流行,直接导致了芸芸学子成绩很高,但解决问题的能力很差。其实,知其然知其所以然,才算真的学明白了。
我属于理论派,我认为工程上的解决方案,一定要有理论做基础。所以在学习并发编程的过程中,我都会探索它背后的理论是什么。比如,当看到 Java SDK 里面的条件变量 Condition 的时候,我会下意识地问,“它是从哪儿来的?是 Java 的特有概念,还是一个通用的编程概念?”当我知道它来自管程的时候,我又会问,“管程被提出的背景和解决的问题是什么?”这样一路探索下来,我发现 Java 语言里的并发技术基本都是有理论基础的,并且这些理论在其他编程语言里也有类似的实现。所以我认为,技术的本质是背后的理论模型。

总结

当初我学习 Java 并发编程的时候,试图上来就看 Java SDK 的并发包,但是很快就放弃了。原因是我觉得东西太多,眼花缭乱的,虽然借助网络上的技术文章,感觉都看懂了,但是很快就又忘了。实际应用的时候大脑也一片空白,根本不知道从哪里下手,有时候好不容易解决了个问题,也不知道这个方案是不是合适的。
我知道根本原因是,我的并发知识还没有成体系。
我想,要让自己的知识成体系,一定要挖掘 Java SDK 并发包背后的设计理念。Java SDK 并发包是并发大师 Doug Lea 设计的,他一定不是随意设计的,一定是深思熟虑的,其背后是 Doug Lea 对并发问题的深刻认识。可惜这个设计的思想目前并没有相关的论文,所以只能自己琢磨了。
分工、同步和互斥的全景图,是我对并发问题的个人总结,不一定正确,但是可以帮助我快速建立解决并发问题的思路,梳理并发编程的知识,加深认识。我将其分享给你,希望对你也有用。
对于某个具体的技术,我建议你探索它背后的理论本质,理论的应用面更宽,一项优秀的理论往往在多个语言中都有体现,在多个不同领域都有应用。所以探求理论本质,既能加深对技术本身的理解,也能拓展知识深度和广度,这是个一举多得的方法。这方面,希望我们一起探讨,共同进步。
欢迎在留言区跟我分享你的经历与想法。感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给更多的朋友。
分享给需要的人,Ta购买本课程,你将得18
生成海报并分享

赞 204

提建议

上一篇
开篇词 | 你为什么需要学习并发编程?
下一篇
01 | 可见性、原子性和有序性问题:并发编程Bug的源头
unpreview
 写留言

精选留言(118)

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

    作者回复: 正解

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

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

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

    作者回复: 好厉害

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

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

    共 2 条评论
    95
  • Minecraft
    2019-02-26
    并发编程学习 第一天 明天去面试 祝我好运
    共 2 条评论
    89
  • crazypokerk
    2019-02-26
    感觉确实如老师所说的,知识不成体系,就像是奶酪,看着是一块,实则满眼孔洞,加油!

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

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

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

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

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

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

    作者回复: 借你吉言

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

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

    共 4 条评论
    22
  • 雷刚
    2020-03-15
    理论确实特别重要。我在数据结构与算法这门课程中,学习到了跳表这种数据结构时,又重新读了一下 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多线程编程核心技术》这本书中,对无锁链表的总结真是面面俱到,只能怪自己这方面的理论欠缺。
    展开

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

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

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

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

    作者回复: 买个专栏啊

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

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

    共 4 条评论
    10
  • balance
    2019-09-20
    并发编程全景图总结:出发点是为了提高【性能】,为了提高性能就得【分工】,分工做事就需要协做,协做即【同步】,在分工协做的同时,存在同时对共享资源的占用、操作的问题,那就带来了共享资源【安全】的问题,解决安全问题的方法就【互斥】。性能是要解决的问题,安全是引出的问题。为什么同时对共享资源的操作会有安全性问题,主要是因为【可见性】、【原子性】、【有序性】问题导致。
    9
  • Joker
    2019-02-28
    这是我在极客学院购买的第一份产品,也是因为纯洁的微笑才买的这份产品,希望自己能坚持下去,在并发编程这方面有点突破

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

    共 4 条评论
    9
  • 拯救地球好累
    2019-07-16
    再谈如何学习并发编程? 1. 高屋建瓴,整体架构->可以画出思维导图 2. 深入本质,直抓核心->理论需要追根溯源,这里的源追到哪儿,对并发编程而言,我觉得到数据结构与算法、操作系统这一层面就足够了 谈谈自己对分工、同步、互斥的理解? 分工。分工其实有两个阶段,一是如何将一个大任务划分成多个小任务,二是如何将多个小任务交给多个线程去协作完成。前者老师称为任务分解,是我们在业务层面需要考虑的问题,有些问题是易于拆分的,如数组求和等,而有些问题的拆分却很难,是否利于拆分非常依赖于问题本身的复杂性和业务模型的设计好坏。后者则是一些并发包里为我们提供的一些分工方法和设计模式中为我们提供的指导法则。 从操作系统的线程模型看分工:以Linux为例,其将线程分为用户级线程、轻量级进程、内核级线程三种,用户级线程处理用户态下的基本任务,而当中断等行为发生时,需要切换到内核态,由内核级线程执行中断服务程序。 分工的实例:Executor,Frok/Join,Feture,各种并发设计模式等 同步。同步是指线程间的协作。线程可以自己独立完成一些子任务,但在完成子任务的过程中或者完成后需要与其他线程交互协作,比如在线程完成一个子任务后需要返回结果给主线程、在子任务完成过程中可能与其他线程有依赖关系,需要等待其他线程某个信号的通知等。 同步的实例:Semaphore,Monitor,CountDownLatch等 互斥。互斥是并发程序对共享变量的保护措施,已达到线程安全的目的。导致共享变量不确定性的核心三大问题是可见性、有序性、原子性问题,而互斥则是解决这些问题的一种较强硬的手段---同一时刻,只有一个线程访问共享变量。 互斥的实例:互斥锁和无锁等 启发: 1. 老师的这种既抓全局又抓原理核心的方式十分有收获,并且尝试自己归纳总结整体概念,《程序员的思维修炼》中曾谈到,我们的学习过程需要右脑思维和左脑思维的结合,右脑看森林,左脑看树木,这也是一种系统化的学习方式,希望在之后学习每一项新技术时都能做到这两点。 2. 同学们对三个概念的理解从追根溯源地从CPU、内存、硬盘等角度思考为什么,很有启发
    展开

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

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

    作者回复: 同感

    8
  • 2019-04-20
    常江舟和Jerry银银两位总结的真棒👍 令宝哥的讲解也甚是到位👍 我的理解: 想理解并发还是要从理解CPU,寄存器,内存,硬盘,外设的性能之差上下手。他们之间的性能之差,导致干的快的空闲等待,这怎么能行?于是就加多了干的慢的人手,这样资源利用率就上来了性能就上来了钱也能赚的更多了。但是问题也随着来了,多任务之间所使用的资源(我认为计算内的资源就是数据,数据必须存在于一定的空间之内,不管数据是临时存储也好,暂时路过也罢,持久存储也一样,所以,换言之计算的资源可以粗略理解为空间)有部分是共享的,自己私有的东西自己随便玩都没事,但是公共的东西必须商量着玩,否则很容易出现更重矛盾。原本计算机的资源,谁能用谁不能用以及什么时候能用什么时候不能用是有计算的灵魂-OS来控制的,但是为了提高其他应用程序的性能更好的发挥计算机的处理能力,其他编程语言也具备了调度系统资源的能力,当然背后必须得到OS的支持,资源的调度势必会涉及到任务怎么分配-分工,共同完成一个大任务怎么协作-协作,为了完成同一个任务大家都在一起有些资源大家共享但是不能乱来,怎么商量谁啥时候能用不能用-同步或互斥。 但是思考的本质还是为了快-快-快,并且不能乱。 更高更快更强,在各个领域人类都有一样追求,只有这样才能超越他人超越自我,获得更好的资源更好的生活。
    展开

    作者回复: 我觉得你的总结也很棒!!!

    5
  • 发条橙子 。
    2019-02-26
    总结 : 并发编程需要构造出一个全景图 。 只要分为三大点 : 分工、协作、互斥。 先将一个大的逻辑按不同的工作去分配给不同的线程 , 这些线程可以同时进行 ,也可以一个线程结束后再进行下一个进程,这时就需要线程间的协作 , 最后如果是多个线程同时进行并且会访问同一个共享资源时就需要对这个资源加锁以便造成资源的不一致 ,这就是互斥 当全景图有了就需要深入到各个点, java sdk 的并发包中提供了很多工具帮我们处理上面三大点, 比如分工的fork/join 、协作的 future 、 互斥的各种锁以及无锁原子类等 。 这只是表面 , 我们更要深入其中了解其背后的理论,比如很多 sdk并发包中的工具都是基于管程的思想 。 了解了这个思想才能举一反三 ,站在更高的视野去理解并发的本质 另外,希望老师也可以着重讲一些管程这类的原理概念,我也是第一次听到这个词甚是感兴趣 , 并且老师说道并发的处理大多涉及操作系统相关的知识,也希望老师能推荐一些书籍或者文章资料便于我们更深入的理解学习
    展开

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

    5