Java并发编程知识总结——开篇词
这篇博客是开始总结Java并发的开篇,主要说下下面总结Java并发编程相关知识的思路、呈现出自己理解的Java并发知识的全景图,为后面Java并发知识总结的复习提供线索和记忆脉络。主要学习和借鉴的主要资料有:《极客时间》并发编程专栏、《Java并发实战》等。
Java并发编程总结思路
- 之前有粗有细的看了一遍《Java并发实战》,看完后过段时间又全部忘记了;究其原因,是因为没有看到Java并发的全局,只看到了局部零散的知识点,记住的是点,难有线和面。因此需要从一个个单一的知识和技术中“跳出来”,建立一张全景图。
- 并发编程领域主要可以抽象成三个核心问题:分工、同步、互斥
分工:
在多核处理器时代,利用多核处理优势,将一个大的任务拆解成一个个小任务分工去完成提高效率。比如要建一条马路,划分成不同的任务:打地基、铺路、铺砖、土建等不同的子任务、分工去完成,提供了工作的效率(性能)。抽象到Java并发上,比如:生产者-消费者模式、Fork/Join、Future(同异步分工协同)等。
同步(协作):
在分工的基础上,子任务之间可能存在依赖关系,比如在造路过程中,土建完成之后需要通知铺路小组去完成铺路,这就是子任务之间的同步。
像这类问题抽象到Java并发上就是:一个线程执行完成了一个任务、如何通知执行后续任务的线程开工的问题。Java提供的Future、同步工具类(CountDownLatch、Notify机制、栏栅CyclicBarrier)等都是解决同步问题的工具。
工作中遇到的线程协作问题,基本可以描述成:当某个条件不满足时,线程需要等待,当某个条件满足时,线程需要被唤醒执行。
互斥(安全性):
分工、同步主要强调的是性能,而并发程序里还有一部分关于正确性的的问题,叫“线程安全”。
并发程序里多个线程同时访问同一个共享变量的时候,结果是不确定的。不确定意味着可能正确,也可能错误,事先是不不确定的。而不确定的主要源头是可见性问题、有序性问题、和原子性问题。为了解决这三个问题,Java语言引入内存模型,内存模型提供了一系列的规则,利用这些规则,可以避免可见性问题、有序性问题,但还是不足以完全解决线程安全问题。解决线程安全问题的核心方案还是互斥。
互斥,指同一时刻,只允许一个线程访问共享变量
互斥的核心就是锁,Java中的synchronized、SDK里的各种Lock都能解决互斥问题。虽说锁解决了安全问题,但同时也带来了性能问题,如何保证安全性的同时有能尽可能提高性能呢?
可以分场景优化,Java SDK里提供ReadWriteLock、StampedLock就可以优化读多写少场景下的锁性能。当然还可以使用无锁的数据结构,例如Java SDK里提供的原子类都是基于无锁技术实现的。
除此之外,还有一些其他的方案,原理是不共享变量或者变量只允许读。这方面,Java提供了ThreadLocal和final关键字,还有一种Copy-on-write模式。
Java并发编程全景图
主要根据《极客时间》并发编程专栏的全景图的基础上加上自己的理解补充完善出来的。后面总结主要会围绕全景图的脉络并以全景图的部分和一个标题分支来命名博客标题。这样我觉得会更方便记忆和查找。
后面全景图会根据反复阅读《并发编程实战》来补充更新完善。
全景图:
基本概念图:
并发工具图
(图片不知道能不能看清楚,思维导图附件我会放到我的博客后台根目录下的xmind目录下)。