11<!-- TOC -->
22
3- - [ Java 并发基础常见面试题总结] ( #java -并发基础常见面试题总结 )
4- - [ 1. 什么是线程和进程?] ( #1-什么是线程和进程 )
5- - [ 1.1. 何为进程?] ( #11-何为进程 )
6- - [ 1.2. 何为线程?] ( #12-何为线程 )
7- - [ 2. 请简要描述线程与进程的关系,区别及优缺点?] ( #2-请简要描述线程与进程的关系区别及优缺点 )
8- - [ 2.1. 图解进程和线程的关系] ( #21-图解进程和线程的关系 )
9- - [ 2.2. 程序计数器为什么是私有的?] ( #22-程序计数器为什么是私有的 )
10- - [ 2.3. 虚拟机栈和本地方法栈为什么是私有的?] ( #23-虚拟机栈和本地方法栈为什么是私有的 )
11- - [ 2.4. 一句话简单了解堆和方法区] ( #24-一句话简单了解堆和方法区 )
12- - [ 3. 说说并发与并行的区别?] ( #3-说说并发与并行的区别 )
13- - [ 4. 为什么要使用多线程呢?] ( #4-为什么要使用多线程呢 )
14- - [ 5. 使用多线程可能带来什么问题?] ( #5-使用多线程可能带来什么问题 )
15- - [ 6. 说说线程的生命周期和状态?] ( #6-说说线程的生命周期和状态 )
16- - [ 7. 什么是上下文切换?] ( #7-什么是上下文切换 )
17- - [ 8. 什么是线程死锁?如何避免死锁?] ( #8-什么是线程死锁如何避免死锁 )
18- - [ 8.1. 认识线程死锁] ( #81-认识线程死锁 )
19- - [ 8.2. 如何避免线程死锁?] ( #82-如何避免线程死锁 )
20- - [ 9. 说说 sleep() 方法和 wait() 方法区别和共同点?] ( #9-说说-sleep-方法和-wait-方法区别和共同点 )
21- - [ 10. 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?] ( #10-为什么我们调用-start-方法时会执行-run-方法为什么我们不能直接调用-run-方法 )
22- - [ 公众号] ( #公众号 )
3+ - [ Java 并发基础常见面试题总结] ( #Java -并发基础常见面试题总结 )
4+ - [ 1. 什么是线程和进程?] ( #1-什么是线程和进程 )
5+ - [ 1.1. 何为进程?] ( #11-何为进程 )
6+ - [ 1.2. 何为线程?] ( #12-何为线程 )
7+ - [ 2. 请简要描述线程与进程的关系,区别及优缺点?] ( #2-请简要描述线程与进程的关系区别及优缺点 )
8+ - [ 2.1. 图解进程和线程的关系] ( #21-图解进程和线程的关系 )
9+ - [ 2.2. 程序计数器为什么是私有的?] ( #22-程序计数器为什么是私有的 )
10+ - [ 2.3. 虚拟机栈和本地方法栈为什么是私有的?] ( #23-虚拟机栈和本地方法栈为什么是私有的 )
11+ - [ 2.4. 一句话简单了解堆和方法区] ( #24-一句话简单了解堆和方法区 )
12+ - [ 3. 说说并发与并行的区别?] ( #3-说说并发与并行的区别 )
13+ - [ 4. 为什么要使用多线程呢?] ( #4-为什么要使用多线程呢 )
14+ - [ 5. 使用多线程可能带来什么问题?] ( #5-使用多线程可能带来什么问题 )
15+ - [ 6. 说说线程的生命周期和状态?] ( #6-说说线程的生命周期和状态 )
16+ - [ 7. 什么是上下文切换?] ( #7-什么是上下文切换 )
17+ - [ 8. 什么是线程死锁?如何避免死锁?] ( #8-什么是线程死锁如何避免死锁 )
18+ - [ 8.1. 认识线程死锁] ( #81-认识线程死锁 )
19+ - [ 8.2. 如何避免线程死锁?] ( #82-如何避免线程死锁 )
20+ - [ 9. 说说 sleep() 方法和 wait() 方法区别和共同点?] ( #9-说说-sleep-方法和-wait-方法区别和共同点 )
21+ - [ 10. 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?] ( #10-为什么我们调用-start-方法时会执行-run-方法为什么我们不能直接调用-run-方法 )
22+ - [ 公众号] ( #公众号 )
2323
2424<!-- /TOC -->
2525
@@ -126,11 +126,8 @@ public class MultiThread {
126126
127127再深入到计算机底层来探讨:
128128
129- - ** 单核时代** : 在单核时代多线程主要是为了提高单进程利用CPU和IO系统的效率。 当我们请求IO的时候,如果java进程中只有一个线程,此线程被IO阻塞则整个进程被阻塞。CPU和IO设备只有一个在运行,那么可以简单地说系统整体效率只有50%。当使用多线程的时候,一个线程被IO阻塞,其他线程还可以继续使用CPU。从而提高了java进程利用系统资源的整体效率。
130-
131- 注意:此种情况是指的计算机只有一个CPU核心,并且假设只运行了一个java进程的情况,多进程的时候,操作系统会调度不同进程占用CPU,也不会存在浪费CPU的问题,只不过是因为大型项目中,作为服务器运行的机器中一般不会运行太多无关进程,所以才可作此假设。
132-
133- - ** 多核时代** : 多核时代多线程主要是为了提高进程利用多核CPU的能力。举个例子:假如我们要计算一个复杂的任务,我们只用一个线程的话,不论系统有几个CPU核心,都只会有一个 CPU 核心被利用到。而创建多个线程,这些线程可以被映射到底层多个CPU上执行,在任务中的多个线程没有资源竞争的情况下,任务执行的效率会有显著性的提高,约等于(单核时执行时间/CPU核心数)。
129+ - ** 单核时代** : 在单核时代多线程主要是为了提高单进程利用 CPU 和 IO 系统的效率。 假设只运行了一个 Java 进程的情况,当我们请求 IO 的时候,如果 Java 进程中只有一个线程,此线程被 IO 阻塞则整个进程被阻塞。CPU 和 IO 设备只有一个在运行,那么可以简单地说系统整体效率只有 50%。当使用多线程的时候,一个线程被 IO 阻塞,其他线程还可以继续使用 CPU。从而提高了 Java 进程利用系统资源的整体效率。
130+ - ** 多核时代** : 多核时代多线程主要是为了提高进程利用多核 CPU 的能力。举个例子:假如我们要计算一个复杂的任务,我们只用一个线程的话,不论系统有几个 CPU 核心,都只会有一个 CPU 核心被利用到。而创建多个线程,这些线程可以被映射到底层多个 CPU 上执行,在任务中的多个线程没有资源竞争的情况下,任务执行的效率会有显著性的提高,约等于(单核时执行时间/CPU 核心数)。
134131
135132## 5. 使用多线程可能带来什么问题?
136133
@@ -146,11 +143,11 @@ Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种
146143
147144![ Java 线程状态变迁 ] ( https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/19-1-29/Java+%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E5%8F%98%E8%BF%81.png )
148145
149- > 订正(来自[ issue736] ( https://github.com/Snailclimb/JavaGuide/issues/736 ) ):原图中 wait到 runnable状态的转换中 ,` join ` 实际上是` Thread ` 类的方法,但这里写成了` Object ` 。
146+ > 订正(来自[ issue736] ( https://github.com/Snailclimb/JavaGuide/issues/736 ) ):原图中 wait 到 runnable 状态的转换中 ,` join ` 实际上是` Thread ` 类的方法,但这里写成了` Object ` 。
150147
151148由上图可以看出:线程创建之后它将处于 ** NEW(新建)** 状态,调用 ` start() ` 方法后开始运行,线程这时候处于 ** READY(可运行)** 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 ** RUNNING(运行)** 状态。
152149
153- > 操作系统隐藏 Java 虚拟机(JVM)中的 READY 和 RUNNING 状态,它只能看到 RUNNABLE 状态(图源:[ HowToDoInJava] ( https://howtodoinjava .com/ " HowToDoInJava ") :[ Java Thread Life Cycle and Thread States] ( https://howtodoinjava .com/java /multi-threading/java -thread-life-cycle-and-thread-states/ " Java Thread Life Cycle and Thread States ") ),所以 Java 系统一般将这两个状态统称为 ** RUNNABLE(运行中)** 状态 。
150+ > 操作系统隐藏 Java 虚拟机(JVM)中的 READY 和 RUNNING 状态,它只能看到 RUNNABLE 状态(图源:[ HowToDoInJava] ( https://howtodoinJava .com/ " HowToDoInJava ") :[ Java Thread Life Cycle and Thread States] ( https://howtodoinJava .com/Java /multi-threading/Java -thread-life-cycle-and-thread-states/ " Java Thread Life Cycle and Thread States ") ),所以 Java 系统一般将这两个状态统称为 ** RUNNABLE(运行中)** 状态 。
154151
155152![ RUNNABLE-VS-RUNNING] ( https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-3/RUNNABLE-VS-RUNNING.png )
156153
@@ -239,7 +236,7 @@ Thread[线程 2,5,main]waiting get resource1
239236
240237** 如何预防死锁?** 破坏死锁的产生的必要条件即可:
241238
242- 1 . ** 破坏请求与保持条件** :一次性申请所有的资源。
239+ 1 . ** 破坏请求与保持条件** :一次性申请所有的资源。
2432402 . ** 破坏不剥夺条件** :占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
2442413 . ** 破坏循环等待条件** :靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
245242
@@ -294,9 +291,9 @@ Process finished with exit code 0
294291
295292## 10. 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?
296293
297- 这是另一个非常经典的 java 多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来!
294+ 这是另一个非常经典的 Java 多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来!
298295
299- new 一个 Thread,线程进入了新建状态。调用 ` start() ` 方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 ` start() ` 会执行线程的相应准备工作,然后自动执行 ` run() ` 方法的内容,这是真正的多线程工作。 但是,直接执行 ` run() ` 方法,会把 ` run() ` 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
296+ new 一个 Thread,线程进入了新建状态。调用 ` start() ` 方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 ` start() ` 会执行线程的相应准备工作,然后自动执行 ` run() ` 方法的内容,这是真正的多线程工作。 但是,直接执行 ` run() ` 方法,会把 ` run() ` 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
300297
301298** 总结: 调用 ` start() ` 方法方可启动线程并使线程进入就绪状态,直接执行 ` run() ` 方法的话不会以多线程的方式执行。**
302299
@@ -309,5 +306,3 @@ new 一个 Thread,线程进入了新建状态。调用 `start()`方法,会
309306** Java 工程师必备学习资源:** 一些 Java 工程师常用学习资源公众号后台回复关键字 ** “1”** 即可免费无套路获取。
310307
311308![ 我的公众号] ( https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/167598cd2e17b8ec.png )
312-
313-
0 commit comments