如何学习Java并发编程
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
2012年我刚转行到互联网,那年夏天我从传统通信行业跳槽到互联网行业。现在回忆起来,真的很感谢自己的决定,除了感谢自己还记得3件事:晴朗的天空、拥挤的地铁以及《一人之下》。
那是我成年后看的第一部国产动画片,可谓惊为天人。里面有所谓的八奇技,其中有一门绝技称为:术之尽头,炁体源流。虽然目前作者还没有揭开谜底,但从定义上来说,炁体源流大概有“追本溯源,回归本质”的含义。
为什么扯这些呢?
很多人学不好Java并发编程,恰恰是因为没有抓住本质。这一部分人学习Java并发编程时,往往都是东一榔头西一棒槌,今天看看Thread,明天学学CountDownLatch,后天又听说线程池不错,最后发现脑中一团浆糊,啥也没记住。
Java为什么能长盛不衰20余载?这大概与它对并发编程的良好支持有一定关系。我目前所在的电商公司早期用的是PHP,开发效率极高、调试简单,在创业初期立下汗马功劳。但随着公司业务高速发展,用户量快速攀升(虽然不知巅峰时期的活跃用户数,但单个业务线的用户表已有9000w),PHP的缺点逐渐暴露。首先是工程大了以后,动态语言确实不太好管理;其次PHP是基于进程的,也就是说一次请求就是一个进程,即使你定义了类变量,也不会存在线程安全问题,但进程的开销要比线程大许多,相对来说性能会差些。
Java、C/C++都是基于线程的,在资源的分配上更快速、粒度更小,但这种做法真的百利而无一害吗?现实生活中并不存在天上掉馅饼的好事,编程世界里也是如此。以数据结构与算法为例,原则上不存在多、快、好、省的万全之策,要么时间换空间,要么空间换时间。Java、C/C++选择了线程,就注定要解决烦人的“线程安全问题”。所有支持多线程的编程语言,注定要在“如何利用多线程高效执行任务”与“如何避免线程安全问题”两座大山之间蜿蜒前行,也由此形成了“并发编程”这个细分领域。
Java并发编程发家史
Java开源至今20余年,对于并发编程的解决方案也在不断改进,所以我们必须承认学习Java并发编程是有一定难度的(这一拳,20年的功力你挡得住吗)。不过好在Java是一个开源项目,老外也知晓“众人拾柴火焰高”的道理,在Java发展的过程中请到了两位贵人。
Josh Bloch:
这位大佬,在JDK 1.2时引入了Java集合。对,就是那个Collection和Map。仔细想想,我们平时除了写new、for循环以外,就是在不断地创建集合容器...可见集合对于Java的重要性。另外,在JDK1.5这个重大版本更新时,Josh Bloch又为Java引入了诸多语言增强,包括拆装箱、foreach等新特性,这才有了我们Java人今天的快活日子啊!
Doug Lea:
JDK1.5注定是划时代的版本,即使是JDK1.8也不如JDK1.5来得惊艳,而JDK1.5的主要缔造者正是Doug Lea,江湖人称 道哥李。
道哥做了啥?让让,我要装逼了:
太多了,不截图了,总之你熟悉的原子类、线程池、ReentrantLock、CompletableFuture啥的都是老爷子写的,以及令人闻风丧胆、八股文必问的AQS也出自他老人家之手...
Doug Lea:傻了吧,整个JUC都是我写的 (墨镜表情包)。
英雄总是惺惺相惜,Josh Bloch和Doug Lea两位大神不仅互相欣赏,偶尔技痒还会结对编程。你问我怎么知道的?我就是那台计算机,当时在现场呢:
如何学习Java并发编程
鉴于大神的水平太高,强烈不建议一上来就去死扣ReentrantLock、AQS,我至今也没有看完AQS的全部代码。我的学习思路是:
- 先理清楚知识脉络
- 自顶向下学习并发编程
- 适当了解底层原理
我个人对Java并发编程的知识分类如下:
那如何自顶向下学习呢?私以为要先了解并掌握多线程的基本用法,分清楚什么是线程、什么是任务,然后再顺着线程产生的问题,学习锁相关的知识。有了锁相关的知识后,再去了解同步工具、线程安全容器、阻塞队列等并发相关的工具。最后学有余力再去扣底层细节,比如CAS、AQS以及基于UnSafe的LockSupport等底层实现。
对于锁及同步容器,其实有一个非常核心的模型需要了解:管程。只有知道了它,才能理解synchronized为什么会提供wait()、notify()、notifyAll()等方法,以及ReentrantLock中的Condition到底是什么。当然,我们无需急躁,后面的章节会慢慢道来。
需要说明的是,在ReentrantLock出来之前,Java其实已经基于synchronized实现了一系列并发容器,比如Hashtable、Vector、Collections.synchronizedList()等。而JDK1.5则通过JUC包提供了新的同步容器,比如ConcurrentHashMap。无论并发容器还是同步容器,只是称谓和实现上的区别,本质还是为了解决并发下的线程安全问题。
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
进群,大家一起学习,一起进步,一起对抗互联网寒冬
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!