多线程这部分内容确实比较高深而且每个知识点之间比较零散,让人摸不着头脑,不知道该从哪里下手。而且对于大部分学生群体来讲,很少有机会接触到高并发这方面的真实场景,平常自己敲代码也基本不会用到,所以也导致我们大部分同学都是面向面经学习,你问 synchronized,叭叭叭我能说一堆,你问 volatile,叭叭叭我也能说一堆,但总感觉差点意思,就是这些知识点是零散的,没有那么一根线把它们很好的串联起来。

所以今天我斗胆造一根线,站在小白的角度,讲讲多线程这部分我们到底要学啥,按照什么样的顺序去学,帮助各位建立一个比较完善的知识体系,形成正确的多线程世界观。后续的文章我也基本上会按照这根线写下来。

山外青山楼外楼,晚辈自知学识尚浅,大佬们若觉得有问题恳请评论区或者私聊我指正,晚辈感激不尽(抱拳)。

炼气
首先,学习多线程,你肯定得知道线程是啥吧,包括线程的一些基础概念(比如上下文切换),那么说到线程,肯定离不开进程。OK,进程和线程这两个概念其实我们在操作系统这门课中都接触过,当然并行和并发、同步与异步等这种基本概念咱也默认你学过,那么你还需要去了解一下 Java 线程和操作系统的线程有啥区别。

另外,容易被大家忽视的一点是,一项技术的出现必定不是凭空捏造的,他一定是为了某个目的而来,在某个成熟的时机应运而生。因此,你需要知道我们为啥要使用多线程,多线程的出现解决了什么问题。

掌握上面这一步,我们称之为炼气,所谓炼精化气,起步阶段需一心一意、沉心静气。

筑基
现在我们已经知道线程是啥了,那在 Java 中如何创建线程呢?为此你会接触到三种创建线程(Thread)的方式:

直接使用 Thread
Thread + Runnable
Thread + Callable + FutureTask
学会了如何创建线程,我们去翻一翻 Thread 类的源码,你会发现其中定义了 Java 线程的六种状态,也就是所谓的生命周期,它和操作系统中线程的五态模型又有啥区别和联系呢?

既然都翻了 Thread 源码,岂有不深究的道理?我们接下来去学习一下 Thread 类给我们提供了哪些控制线程的方法,它们分别能干啥,怎样影响了线程的状态:

start / run
sleep / yield
join / join(long n)
interrupt
setDaemon 守护线程
这一阶段的学习,也就是入门阶段后的第一步,我们称之为筑基。基础不牢,地动山摇。

金丹
诚然,一个程序顺序的运行多个线程本身是没有问题的,但是如果多个线程同时访问了某个共享资源,就可能会发生不可预知的现象,也就是我们常说的线程安全问题,要了解这些问题产生的根本原因,我们就需要去深刻的了解 Java 内存模型(Java Memory Model,JMM)。

为此,我们会学习到和线程安全息息相关的三大性质:

1)原子性:一个操作是不可中断的,要么全部执行成功要么全部执行失败(也可以说是提供互斥访问,同一时刻只能有一个线程对数据进行操作)

2)可见性:当一个线程修改了共享变量后,其他线程能够立即得知这个修改

3)有序性:编译器和处理器为了优化程序性能,会对指令序列进行重新排序。由于重排序的存在,可能导致多线程环境下程序运行结果出错的问题。

那么编译器和处理器在重排序时会遵守什么原则呢?为此你会了解到数据依赖性和 as-if-serial,这里简单介绍一下这两个概念:

编译器和处理器在重排序时,会遵守数据依赖性,它们不会改变存在数据依赖性关系的两个操作的执行顺序
as-if-serial 语义的意思是:不管怎么重排序,程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守 as-if-serial 语义
事实上,可见性和有序性其实是互相矛盾的两点。一方面,对于程序员来说,我们希望内存模型易于理解、易于编程,为此 JMM 的设计者要为程序员提供足够强的内存可见性保证,专业术语称之为 “强内存模型”。而另一方面,编译器和处理器则希望内存模型对它们的束缚越少越好,这样它们就可以做尽可能多的优化(比如重排序)来提高性能,因此 JMM 的设计者对编译器和处理器的限制要尽可能地放松,专业术语称之为 “弱内存模型”。

当然,对于这个问题,JMM 的设计者找到了一个很好的平衡点,那就是 happens-before,这是 JMM 最核心的概念!理解 happens-before 是理解 JMM 的关键。

知其然而知其所以然,这一阶段,我们称为金丹。

渡劫
具体到 Java 语言层面,是怎么保证线程安全的呢?也就是如何保证原子性、可见性和有序性呢?(保证有序性上文已经说过了,就是使用 happens-before 原则)。

1)对于可见性,可以使用 volatile 关键字来保证,不仅如此,volatile 还能起到禁止指令重排的作用;另外, synchronized 和 final 这俩关键字也能保证可见性。

2)对于原子性,我们可以使用锁 和 java.util.concurrent.atomic 包中的原子类来保证。(给萌新解释一下,java.util.concurrent,简称 J.U.C,就是一个包,也称为并发包。现在网上大部分博客都会直接说 JUC,对萌新不是很友好),我们可以看看 juc.atomic 中有哪些类:

当然, atomic 包下这些原子操作类保证原子性最关键的原因还是因为它们使用了 CAS 操作,于是,你需要先去深入学习一下 CAS,了解 CAS 存在的三个问题,然后再去挖一挖这些原子类的底层原理。

另外,上面我们提到的锁这个话题其实又是一个非常核心的知识点,在深入学习之前,你需要了解一下各种锁的概念:

悲观锁和乐观锁
重量级锁和轻量级锁
自旋锁
偏向锁
重入锁和不可重入锁
公平锁和非公平锁
共享锁和排他锁
另外,与锁相关的概念的还有临界区、竞态条件等,这些你都是要去了解的。

那么锁在 Java 中具体是怎么实现的呢?早先 Java 程序是靠 synchronized 关键字实现锁功能的,在我们掌握了 synchronized 的使用方式以及底层原理后,你还会接触到与 synchronized 配套的 wait/notify/notifyAll 方法。

在 Java SE 5 之后,并发包 JUC 中新增了 Lock 接口以及相关实现类(放在 java.util.concurrent.locks 包下)也可以用来实现锁功能。

为什么会新增这样一个 Lock 接口及其相关实现类呢?因为使用 synchronized 关键字会隐式地获取锁,但是它将锁的获取和释放固化了,也就是先获取再释放。当然,这种方式简化了同步的管理,可是扩展性没有显示的锁获取和释放来的好。

例如,针对一个场景,手把手进行锁获取和释放,先获得锁 A,然后再获取锁 B,当锁 B 获得后,释放锁 A 同时获取锁 C,当锁 C 获得后,再释放 B 同时获取锁 D,以此类推。这种场景下,如果使用 synchronized 关键字就不那么容易实现了,而使用 Lock 却容易许多。

它提供了与 synchronized 关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种 synchronized 关键字所不具备的同步特性。

另外,还有一点非常重要的是!我们可以去翻一翻实现了 Lock 接口的类,比如 ReentrantLock(大部分文章都会直接把它翻译成重入锁),你会惊讶的发现它并没有多少代码,基本所有的方法都是调用了其静态内部类 Sync 中的方法,而 Sync 类继承了 AbstractQueuedSynchronizer 类(也就是大名鼎鼎的 AQS,译为队列同步器,简称同步器)。

可以把 AQS 理解为一个用来构建锁和同步器(工具类)的框架,locks 包中的各种锁以及接下来我们会学习的 JUC 中的工具类都是基于 AQS 来实现的。

OK,关于 AQS 这篇文章就不再多说了。上面我们提到了三个并发关键字,synchronized、 volatile,和 final,可能很多小伙伴都不知道,啥?final 和并发有啥关系?当然,这些,后续文章都会写的。

本阶段的知识非常重要,并且相对来说知识点比较多也比较难,因此我们称之为渡劫。

大乘
渡劫完毕,走到这一步各位对多线程基本的知识架构已经有了一定的认知,世界观已经初步形成,最后,就是补强的过程了,我们来看看 J.U.C 这个包还有什么东西(下图没有截全):

JUC 其实可以分为五大类:

Lock 框架(locks 包)
原子类(atomic 包)
并发集合
线程池
工具类
后面三种正是我们在这一阶段需要学习的。并发集合和线程池就没啥好说的了,它们的知识点都比较集中,学习目标也很明确,网络上很容易就能找到一篇条理清晰的文章。

然后常用的工具类还是有必要学习下:

CountDownLatch
CyclicBarrier
Semaphore
Exchanger
所谓工具类嘛,那一定是封装了某些比较复杂的操作,使我们可以很简单的去完成这些操作。以 CountDownLatch 为例:在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用 Thread 类的 join 方法,让主线程等待被 join 的线程执行完之后,主线程才能继续往下执行。而 Java 并发工具类中为我们提供了这样一个类似 “倒计时” 的工具类 CountDownLatch,可以十分方便的完成这种业务场景。

另外,还有一个比较重要的类,我也不知道怎么给它分类,就是 ThreadLocal,江湖人称线程隔离术,必问高阶考点。

OK,学完了本阶段,多线程世界观已完整形成,我们称之为大乘,忘我之境,全在己心。

最后

这些知识点的导图和问题的答案详解的PDF文档都可以免费分享给大家.需要资料的小伙伴点赞关注博主,私信博主“学习”或者“资料”即可获得免费资料!

面试经验|春招在即,时间宝贵,这一定是最近的 Java 并发学习路线相关推荐

  1. 面试上机器-将当前时间以数码时钟的方式控制台显示(Java实现)

    面试上机器-将当前时间以数码时钟的方式控制台显示(Java实现) 前言 毕业近2年了,写下人生中的第一篇:博客,不喜轻喷,不断进步,希望通过文字记录我的程序人生 : 废话 此次记录一次面试上机题,将当 ...

  2. 渣硕自学两年转行Android,零经验春招拿美团30w年薪offer,HR说我是头一个!

    前言 本人为某末流211工科硕士, 找工作时,经常在网上找资料学习.面经刷题,为回馈朋友们,写下这篇分享贴,也算是对我求学生涯的总结. 说来令人感慨,我的考研之路异常曲折,每次都觉得自己能十拿九稳,结 ...

  3. 简简单单记录一下我今年第一次面试,春招美的研发岗面试经历分享!

    前言 秋招已过,春招也准备开始了,很感谢站内各位大佬的面经分享,我也来写点面经反馈给大家吧.废话不多说,先给大家讲一下面试的流程: 12月20日当天晚上开始网申投简历 1月4日收到测评邮件和链接,然后 ...

  4. 20W字纯手打Java并发学习笔记,助力你金三银四,决战春招,必进大厂

    假如阿里给了你这个机会,你却卡在三面,你会不会懊恼? 假如阿里真的让你通过,只需要你把这一块技能的底层原理摸透,你学不学? 我有一个朋友,他小厂背景.15年毕业.普通学校,这看起来确实没什么战斗力,但 ...

  5. Java程序员春招三面蚂蚁金服,1-3年Java开发工程师面试经验分享

    前言 为什么互联网资讯这么发达,但是没有出现技术人才井喷? 为什么会出现应届生薪资倒挂多年老员工的现象? 这个世界有太多的现象都可以用**"二八定律"**来解释. 20%拿着高工资 ...

  6. 博彦科技笔面试-2019春招

    19/3/27下午参加了博彦(西安)的Java技术岗笔试 题目比较简单,不过对我来说有些难,Java好久没碰过了. 根据后序和中序序列重建树,本来会的,但是做错了(遗憾). 数据库操作有一个统计平均值 ...

  7. java怎么输出liststring_春招|春招实习上岸,分享面筋回报社区(Java、Python)...

    作者:小瓜子Jack 链接:https://www.nowcoder.com/discuss/172824

  8. 经验分享 | 我的八股文学习路线及攻略

    前几天拿到字节offer了,很开心,也有很多小伙伴私信我问了很多问题,所以在这里简单分享一下我是如何学习八股文的,文章篇幅略长,希望能帮助到有需要的同学或者也是双非大三正在迷茫的你. [知识库分享] ...

  9. 2020德勤面试开始了吗_四大2020年春招时间曝光!

    寒假来了,开心之余,小可爱们是不是也会为工作头秃? 尤其是应届毕业生,想想过年的时候一堆亲戚会跑过来"关心"就头皮发麻: "毕业后去哪儿啊,定了没?" &quo ...

最新文章

  1. 创建springboot出现error:connection timed out创建springboot报错显示连接超时解决方案
  2. Oracle约数,Oracle约束简介
  3. 移植U-BOOT之裁剪和修改默认参数(易用性)启动内核,以及对uboot进行分区
  4. springboot项目接入配置中心,实现@ConfigurationProperties的bean属性刷新方案
  5. C# SNMP 编程
  6. bootstrap table 表格支持shirt 多选_bootstrap-table 表格行内编辑实现
  7. 彻底解决Eclipse的控制台console按钮非常小
  8. eclipse中设置JVM内存
  9. word排版程序代码
  10. 一个朋友写的诗词收藏
  11. Excel常用电子表格公式大全1-1
  12. 2020年软件工程保研南大、国防科大、天大、同济、南开、北理、软件所、哈工大、哈工深、复旦经验分享
  13. 老外网络语言缩写总结
  14. 七雄争霸如何获得鸿蒙碎片,七雄争霸手游资源如何获取
  15. Mac鼠标光标消失怎么办?苹果电脑鼠标指针不显示的解决方法
  16. Why WebRTC|前世今生
  17. 学校计算机房电脑桌,学校机房用双机位电脑桌的制作方法
  18. 数据挖掘——机器学习
  19. Spark Bloom Filter 测试
  20. 《实战Java高并发程序设计》.pdf

热门文章

  1. 使用函数求Fibonacci数
  2. K3忘记帐套管理员密码的解决办法
  3. android 手机屏幕解锁最多有多少种?
  4. ps暂存盘已满的解决办法
  5. “浅薄”绝不该是中国程序员的性格特征
  6. 软件开发人员意向移民加拿大的可以点击
  7. 【Windows下删除git凭据】
  8. Word使用编码的方式实现第?页共?页(可自定义起始页和总页数)(步骤超级详细)
  9. 高级程序员、研发Leader、技术总监、首席架构师、CTO的职责
  10. 微芯研究院一面4.2