前言以及知识点要掌握到什么程度
毋庸置疑,多线程的知识点非常多,又杂又深,那多线程的知识点要掌握到什么程度呢?
- 要掌握多线程的基础知识,包括线程的介绍和线程调度基本原理;
- 了解多线程为什么会有安全问题?我们怎么实现线程安全;
- 掌握多线程优化的方法,包括线程之间的协作方式。
如何学习?
多线程的知识点有依赖关联性,所以学起来顺序很重要:
开篇:首先我们要一路溯源下去,为什么会有并发问题?因为硬件工程师优化之后给软件工程师留了坑。为什么要用多线程?因为要平衡CPU和存储的速度差异。那这些优化带来了什么问题呢?知道了并发问题产生的原因之后,才明白【内存模型】要解决的问题 —— 按需禁用优化和缓存。
基础:学习【内存模型】相关的概念和知识,熟练使用多线程的基础【Thread 类】,知道Thread 线程的基本概念、状态,还有 wait,notify,join 等多线程基本的通信手段。了解过 Thread 之后,我们就要狠扎多线程的基础理论点了,我们要搞懂关键字 【synchronized】和 【volatile】,并且结合第一步学到的【JMM内存模型】来深入体会这 2 个关键字的作用和内存屏障。
进阶:现在我们就知道为什么我们要减少创建线程对象的数量,【线程切换】会带来严重的性能问题,包括:线程上下文切换,线程状态的切换。这就引申出了【锁】、【CAS 原子算法】、【JVM 多锁的优化】、【重入锁】。
应用:到此为止,我想大家对于多线程的理论至少已经有了基本的概念,接下来就要学习多线程的核心:【线程池】 ,除了原理,还要学习在各个【异步库】中,是怎么根据实际场景自定义线程池的,比如 AsyncTask、IntentService、OkHttp。
末章:最后,别忘了,Java 的【并发集合】,我们从2个方面看: (1)用锁的手段来解决并发问题,如 AQS、ConcurrentHashMap; (2)用COW思想来解决并发问题,如 CopyOnWriteArrayList。
相信按照这个顺序,多线程和并发学起来并不吃力,面试官的问题都难不倒你了。
思考:无论学习什么知识点,别忘了思考建立联系,如果只是生搬硬套,就无法做到融会贯通,举个例子:
----------------------- 小场景 -----------------------
面试官:run 结束线程还能复活吗?
面试者:不能了。
面试官:既然 run 方法执行完线程就销毁了,那么线程池是怎么做到线程复用的?
面试者:。。。。。
如果你分开学习线程和线程池,面对这个问题可能会束手无策,很显然,线程池一个很显著的特征就是“长期驻留了一定数量的活线程”,既然线程要活,那就不能太快销毁,那怎么办呢?那就让 run 永远都不要执行完成呀!(除了超时)加个 while 循环,从任务队列中取任务,要么一直阻塞要么等到超时,超时到了的时候,这个线程也就走到了生命的尽头。
开篇 - 博文
本文跨度很大,不仅介绍了线程和调度的基本原理,还有实现线程安全的方案,更有Android中执行异步任务的方式介绍,建议多读几遍。
诚然,这就是我非常欣赏的文章格式,从需求来 设计、反推 源码。如果一来就啃源码,难免会 纠结于实现细节 而 忽略了业务场景,毕竟设计是不断迭代出来的。
说出线程池的自定义参数如何设置,大家可以 balabala 熟练地背诵出来,但是如果问:核心线程能不能销毁?你是如何理解核心线程的?能不能动态修改核心线程数和最大线程数?死记硬背的知识可就无能为力了。
附带一句,数据结构学起来枯燥无味?那是因为没有和实际场景所结合,比如 PriorityBlockingQueue 应用在哪?线程池的自定义策略很眼熟吧。glide 的自定义线程池策略就用了 PriorityBlockingQueue 实现 DecodeJob 解码任务支持优先级调度。
一般这类博文,我会用来做源码阅读的辅助,带着问题和目的读源码,你才会留意到设计里的精妙细节。
应用 - 博文
总结很到位,结合了不同场景分析解决并发问题的处理方式。
知识点都懂了?别急,来刷几道题目巩固一下,别看题目不少,来来去去其实就几种类型:
- 线程交替执行 —— AB AB 型
- 线程依赖执行 —— ABC 型
- 线程安全
线程交替执行+线程依赖执行
并发库
从整体上来看 concurrent 包的整体实现图如下图所示:
最底层是上一层的实现基础。举个例子,图中可见,所有锁的原理都是 AQS,而 AQS 底层又用到了大量的 volatile+CAS。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论