0、问题大纲
一、概念与工具
1、进程和线程
- 追问1:Java线程有几种状态?
2、什么是线程安全,怎么保证多线程线程安全?(*4)
3、线程的局部变量
- 追问1:为什么安全?
- 追问2:如何跨越方法边界呢?
4、什么情况下Java程序会产生死锁?(*2)如何定位、修复?(*2)【第18讲】(死锁处理办法)
- 追问1:Java调试命令。看线程运行状态用什么?看堆栈信息用什么?
5、如何终止一个正在运行的线程?
- 追问1:如何优雅终止线程池?
一、概念与工具
1、进程和线程
进程是最小资源分配单位,线程是最小运行单位,线程们共享同一个进程的内存空间等资源。一个进程下面能有一个或多个线程,每个线程都有独立一套的寄存器和栈,这样可确保线程控制流相对独立。
补充:
1、协程是为了避免线程IO阻塞,能去做其他事情,因此把程序逻辑封装在叫协程的抽象里。
追问1:Java线程有几种状态?
追问2:线程等待时位于哪个区域,具体讲一下
……(暂时不太清楚)
2、什么是线程安全,怎么保证多线程线程安全?(*4)
线程安全:不同线程访问相同资源而不会产生错误或不可预知结果。
保证方式:synchronized、Volatile、并发工具类、Reentrant Locks等
补充:
方式 | 内容 | 具体 |
---|---|---|
并发集合 | java.util.concurrent包 | ConcurrentHashMap() |
原子对象 | AtomicInteger、AtomicLong、AtomicXXX…… | |
同步方法 | synchronized修饰方法/语句 | synchronized关键字 |
Volatile | 解决线程间可见性问题,确保JVM读取/写入主内存,而不是CPU缓存。 | Volatile修饰变量 |
Reentrant Locks | 改进的Lock实现 | ReentrantLock |
读/写锁 | 可以实现没有线程写,就可以有许多线程读取该资源,否则阻止其他线程取 | ReadWriteLock |
无状态实现 | ||
不可变实现 | ||
线程本地变量 | 字段本地化,线程间不会共享 | |
同步集合 | Collections.synchronizedCollection() | |
外部锁定 |
……
3、线程的局部变量
局部变量:方法内部的变量。
//生成斐波那契数列
public int[] fibonacci(int n){
//存放结果的数组
int[] result = new int[n];
//数组的第1项和第2项为1
result[0] = result[1] = 1;
//计算第3项到第n项
for(int i = 2; i < n; i++){
result[i] = result[i-2] + result[i-1];
}
return result; // 调用result生成斐波那契数列,result是安全的
}
不涉及到数据竞争,是线程安全的。
追问1:为什么安全?
局部变量就是存放在调用栈里的,栈帧在调用方法时创建,返回时销毁。
而每个线程有自己独立的调用栈,所以不存在并发问题。
追问2:如何跨越方法边界呢?
变量必须创建在堆里。
4、什么情况下Java程序会产生死锁?(*2)如何定位、修复?(*2)【第18讲】(死锁处理办法)
死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此一直处于等待之中,没有任何个体可以继续前进。死锁不仅仅是在线程之间会发生,存在资源独占的进程之间同样也可能出现死锁。通常来说,我们大多是聚焦在多线程场景中的死锁,指两个或多个线程之间,由于互相持有对方需要的锁,而永久处于阻塞的状态。
你可以利用下面的示例图理解基本的死锁问题:
定位死锁最常见的方式就是利用 jstack 等工具获取线程栈,然后定位互相之间的依赖关系,进而找到死锁。如果是比较明显的死锁,往往 jstack 等就能直接定位,类似 JConsole 甚至可以在图形界面进行有限的死锁检测。
如果程序运行时发生了死锁,绝大多数情况下都是无法在线解决的,只能重启、修正程序本身问题。所以,代码开发阶段互相审查,或者利用工具进行预防性排查,往往也是很重要的。
追问1:Java调试命令。看线程运行状态用什么?看堆栈信息用什么?
……
5、如何终止一个正在运行的线程?
stop():一剑封喉,被终止线程没机会料理后事,不建议使用。
interrupt():可以将休眠线程转换为RUNNAVBLE状态,设置中断位,然后判断是否中止。
……
追问1:如何优雅终止线程池?
方法:shutdown()和shutdownNow()
shutdown():保守,执行后,不接收新任务,但会等待正在执行和阻塞任务执行完,才最终关闭。
shutdownNow():激进,拒绝新任务,同时强制停止正在执行与阻塞队列任务,优雅结束需要正确处理线程中断。
二、参考
1、程序员必需清楚的进程和线程
2、Kotlin 协程实践之进程、线程、协程
3、进程、线程与协程还傻傻分不清?P7 大佬大白话讲解,直接秒懂
4、09 | Java线程(上):Java线程的生命周期
5、什么是线程安全?如何实现?
6、【高并发】面试官问我:为什么局部变量是线程安全的?
7、35 | 两阶段终止模式:如何优雅地终止线程?