转载

面向面试的Java并发基础整理

Java并发编程是后端面试的常见问题,自己之前没有系统学习过这方面的内容,在面试中直接被问倒了。踩一坑填一坑,这篇算是一份个人整理的学习笔记,目的是串联Java并发的基础知识,能和面试官聊上几句。

概述

一般而言,并发编程是应用各种编程语言中的必修内容,然而如果没有深入实践,似乎只能照本宣科背自己用过几个synchronized,volatile关键字(以Java为例),这当然不是学习的目的。 [1] 中建议 ”先要在脑海里有一个完整的并发知识体系,然后根据这个体系去不断完善这个体系里每个模块的细节 “,这才是学习的目的。然而,从功利角度而言,面试经常考,准备时间有限,再仔细啃完几本并发书籍估计秋招都结束了。本文题所谓”面向面试“,即是解决面试官问到时只能答”我不知道“的尴尬,同时也给出一些精进的学习方向。

几个概念

线程与进程

Wiki上关于进程(process)和线程(thread) 二者的解释如下:

”a process is the instance of a computer program that is being executed.“

“a thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler, which is typically a part of the operating system.

简而言之,进程是指操作系统中运行着的程序,而线程则是更细粒度的划分,是操作系统能够进行调度的最小单位,两者属于包含关系。根据 [2] 的说法 — ”进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同。“ [3] 给出了一个更形象的比喻,便于理解梳理二者的关系。

并发与并行

[4] 中给出了并发(Concurrent)和并行(Parallel)的区别,并发单CPU看起来“同时干多件事”,而并行则是不同任务在不同CPU上同时进行,互不抢占。

面向面试的Java并发基础整理
并发和并行的关系,咖啡机理解为CPU即可。

线程安全

线程安全(thread safety)是指 “某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。” (Wiki)

线程池

线程池(thread pool)是一种线程的使用模式,其维护多个线程,避免了处理短时间任务时创建和销毁线程的代价。好处是降低资源消耗和提高线程的可管理性质, [5] 中给出了Java中线程池的使用实例。

常见面试问题整理

Java中如何创建一个线程

[6] 总结了Java中三种创建线程的方法:

1.实现 Runnable 接口

Runnable 接口是Java自带的用于线程实现的接口,其只有一个 run() 方法,如果我们想要创建线程,可以当前类继承 Runnable 接口,同时实现其 run() 方法,在调用时,我们首先需要实例化对象,然后再调用 start() 方法来运行当前进程。

2.继承 Thread 类

第二种方法是继承 Thread 类,使用过程与1几乎一样, 必须重写 run() 方法,使用时也需要调用 start() 方法。查看源码可以发现, Thread 类本质上是 Runnable() 接口的一个实例,其提供了一些处理线程的方法可被直接调用(如调整线程优先级,终止线程等)。

3.通过 Callable 和 Future 创建线程

  • 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值;
  • 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值;
  • 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程;
  • 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

该种方式可以在线程执行后获得返回结果。

三种方法的具体实例可参考 [6] 。

synchronized 关键字

实现线程安全是实践多线程编程中非常重要的点,在 Java 中,我们可以通过使用 synchronized 来给代码片段或方法加锁,保证线程操作的互斥性(也称原子性)和可见性。

[7] 中给出了 synchronized 非常详细的解释和实例。简而言之,当使用 synchronized 来修饰一个方法或代码块时,可以保证在同一时刻最多只有一个线程执行该代码,其他线程必须等待当前线程执行完成后才能获得该部分代码的锁,从而获得执行代码的权限。

下一步

[8] 系统总结了 Java 多线程的各种场景,可以作为一个不错的梳理知识点的课程。

可以看出,并发体系多而杂,想一蹴而就让有水平的面试官认为你很懂线程,基本是不可能的事情。先通过 小实践+半背半理解 通过面试,之后再在实践中不断打磨这方面的技能才是真理。

参考

[1] 面试中并发类问题的准备和学习

[2] 线程和进程的区别是什么?

[3] 进程与线程的一个简单解释

[4] 深入理解Java并发编程(一):到底什么是线程安全

[5] Java并发编程:线程池的使用

[6] Java 多线程编程

[7] java synchronized详解

[8] 马士兵老师高并发编程系列

ChangeLog

20190324,创建并完成v1.0。

3 total views, 3 views today

原文  https://pengcheng.tech/2019/03/24/面向面试的java并发基础整理/
正文到此结束
Loading...