【面试】Java并发篇(一)

0、问题大纲

一、概念与工具

1、进程和线程
 - 追问1:Java线程有几种状态?

2、什么是线程安全,怎么保证多线程线程安全?(*43、线程的局部变量
 - 追问1:为什么安全?
 - 追问2:如何跨越方法边界呢?

4、什么情况下Java程序会产生死锁?(*2)如何定位、修复?(*2)【第18讲】(死锁处理办法)
 - 追问1:Java调试命令。看线程运行状态用什么?看堆栈信息用什么?

5、如何终止一个正在运行的线程?
 - 追问1:如何优雅终止线程池?

一、概念与工具

1、进程和线程

进程是最小资源分配单位,线程是最小运行单位,线程们共享同一个进程的内存空间等资源。一个进程下面能有一个或多个线程,每个线程都有独立一套的寄存器和栈,这样可确保线程控制流相对独立。
1

补充:
1、协程是为了避免线程IO阻塞,能去做其他事情,因此把程序逻辑封装在叫协程的抽象里。
追问1:Java线程有几种状态?

2

追问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:为什么安全?

局部变量就是存放在调用栈里的,栈帧在调用方法时创建,返回时销毁。
4
而每个线程有自己独立的调用栈,所以不存在并发问题。
5

追问2:如何跨越方法边界呢?

变量必须创建在堆里。

4、什么情况下Java程序会产生死锁?(*2)如何定位、修复?(*2)【第18讲】(死锁处理办法)

死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此一直处于等待之中,没有任何个体可以继续前进。死锁不仅仅是在线程之间会发生,存在资源独占的进程之间同样也可能出现死锁。通常来说,我们大多是聚焦在多线程场景中的死锁,指两个或多个线程之间,由于互相持有对方需要的锁,而永久处于阻塞的状态。

你可以利用下面的示例图理解基本的死锁问题:
9

定位死锁最常见的方式就是利用 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 | 两阶段终止模式:如何优雅地终止线程?

猜你喜欢

转载自blog.csdn.net/HeavenDan/article/details/112613534