- 并发篇
- 1. 什么是线程和进程?
- 2. 程序计数器为什么是私有的?
- 3. 虚拟机栈和本地方法栈为什么是私有的?
- 4. 如何理解线程安全和不安全?
- 5. 线程的类型
- 6. 如何创建线程?
- 7. 线程的生命周期和状态
- 8. 什么是死锁,死锁产生的条件
- 9. 如何预防和避免线程死锁?
- 10. sleep() 方法和 wait() 方法对比
并发篇
1. 什么是线程和进程?
答:
- 进程: 进程就是一个程序的实例。每个进程都拥有独立的内存空间,进程之间内存不共享。进程间的切换开销比较大。
- 线程: 线程是进程中的一个执行单元,一个进程可以包含多个线程。线程共享进程的内存空间。线程间的切换开销小。
2. 程序计数器为什么是私有的?
答:
- 程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。
3. 虚拟机栈和本地方法栈为什么是私有的?
答:
- 为了保证线程中的局部变量不被别的线程访问到
4. 如何理解线程安全和不安全?
答:
- 线程安全: 不管有多少个线程同时访问,都能保证这份数据的正确性和一致性。
- 线程不安全: 多个线程同时访问时无法保证数据的一致性,正确性。
5. 线程的类型
答:
- IO 密集型:IO 密集型的线程主要进行输入输出操作,如读写文件、网络通信等,需要等待 IO 设备的响应,而不占用太多的 CPU 资源。
- CPU密集型:CPU 密集型的线程主要进行计算和逻辑处理,需要占用大量的 CPU 资源。
6. 如何创建线程?
答:
- 继承
Thread
类,重写run
方法 - 实现
Runnable
接口 - 实现
Callable
接口 (可以获得线程的返回结果) - 使用线程池
7. 线程的生命周期和状态
答:
8. 什么是死锁,死锁产生的条件
答:
- 死锁: 线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,又不释放自己资源,所以这两个线程就会互相等待而进入死锁状态。
产生死锁的四个必要条件:
- 资源互斥:该资源任意一个时刻只由一个线程占用。
- 请求与保持条件:线程在请求资源而阻塞时,不会释放已持有的资源。
- 不剥夺条件:线程持有的资源不会被其他线程抢夺。
- 循环等待条件:线程对资源的请求形成一个闭环。例如,线程 A 等待线程 B 持有的资源,线程 B 等待线程 C 持有的资源,以此类推,直到某个线程又开始等待线程 A 持有的资源。
9. 如何预防和避免线程死锁?
答:
破坏死锁的产生的必要条件即可:
- 破坏请求与保持条件:一次性申请所有的资源。
- 破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
- 破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
避免死锁就是在资源分配时,借助于算法(比如银行家算法
)对资源分配进行计算评估,使其进入安全状态。
安全状态 指的是系统能够按照某种线程推进顺序(P1、P2、P3……Pn)来为每个线程分配所需资源,直到满足每个线程对资源的最大需求,使每个线程都可顺利完成。称 <P1、P2、P3…Pn> 序列为安全序列。
10. sleep() 方法和 wait() 方法对比
答:
共同点:两者都可以暂停当前线程的执行。
区别:
sleep()
方法没有释放锁,而wait()
方法释放了锁 。wait()
通常被用于线程间交互/通信,sleep()
通常被用于暂停执行。wait()
方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()
或者notifyAll()
方法。sleep()
方法执行完成后,线程会自动苏醒。或者也可以使用wait(long timeout)
超时后线程会自动苏醒。sleep()
是Thread
类的静态本地方法,wait()
则是Object
类的本地方法。