八股文骚套路之Java并发
线程
什么是线程和进程
进程:是程序一次执行的过程,是系统运行程序的基本单位。系统一个程序的运行就是一个程序从创建、运行到消亡的过程
线程:在Java中,启动一个main函数就是启动了一个JVM进程,而main函数所在的线程就是这个进程中的一个线程,也称为主线程
[!TIP]
用户线程和内核线程的区别和特点主要体现在:1.创建线程和切换线程的成本 2.能否利用多核
线程和进程的区别
- 进程是独立的,但是线程之间则不一定,同意进程中的多个线程极有可能会相互影响(共享堆和方法区)。
- 进程开销大,线程开销小,但是线程不利于资源的管理和保护
程序计数器的作用,为什么要私有?
- 进行代码的流程控制
- 记录当前线程执行的位置
所以计数器的私有化主要是为了保证线程切换后能恢复到正确的执行位置
虚拟机栈和本地方法栈为什么是私有的?
为了保证线程中的局部变量不被别的线程访问到
如何创建线程
严格来说 Java中只有 new Thread.().start
能创建线程
线程的生命周期
- new 创建了还没start
- runnable 运行 被start等待运行的状态
- blocked 阻塞 等待释放
- waiting 等待,表示需要等待其他线程执行完一些特定动作
- time_waiting 超时等待 可以在等待一定时间之后自行返回
- terminated 线程终止
多线程
多线程和单线程的区别
总体来说:
- 线程可以看作轻量级的进程,是程序执行的最小单位,线程间切换和调度的成本比较小。多核cpu可以让多个线程同时运行,减少线程上下文切换的开销
- 现在的系统要求的并发量很高,多线程并发编程是开发高并发系统的基础,利用好多线程机制可以大大提高系统整体的并发能力和性能
从计算机底层来说:
以前计算机是单核的时候,多线程主要是为了提高单个进程利用cpu和io系统的效率。当一个进程被阻塞的时候,让其他进程继续使用cpu
现在多核时代,主要谁为了提高进程利用多核cpu的能力。如果只用一个线程,无论系统有几个核心,都只有一个核心被用到,而创建多个线程,可以让这些核心都被充分利用起来。
资源使用量:单线程消耗资源少,管理和调试简单,无法充分利用多核cpu的优势。多线程管理相对复杂,需要处理线程之间的同步问题以防止出现资源竞争和死锁等问题
响应性:单线程如果某个操作阻塞了进程,那么整个程序都会停滞;多线程中及时一个线程被阻塞,其他线程仍然可以继续执行任务
编程复杂性:单线程不用考虑同步、死锁等问题;多线程需要处理线程之间的数据同步,以避免资源竞争(使用互斥锁、信号量等工具)
应用场景:单线程应用于简单的任务,例如脚本和轻量级应用;多线程应用于cpu密集型或I/O密集型的复杂任务,如网络服务器、游戏引擎、数据处理等等。
同步和异步的区别
- 同步:发出调用之后一致等待调用的结果
- 异步:发出调用之后,不用等待返回结果,该调用就可以直接返回
单核cpu支持多线程吗
- 支持,可以采用时间片轮转将cpu资源分配给不同的线程
使用多线程可能带来什么问题
- 并发编程的目的就是为了提高程序的执行效率进而提升程序的运行速度,会遇到内存泄漏、死锁、线程安全性问题等等
如何理解线程的安全和不安全
- 线程安全:指多线程环境下,对于同一份数据,不管有多少个线程同时访问,都能保证这份数据的正确性和一致性。
- 线程不安全: 对于同一份数据,多个线程同时访问的时候可能会导致数据混乱、错误或者丢失。
死锁
什么是线程死锁?
多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止
死锁的四个必要条件和预防和避免线程死锁的方法
- 互斥
- 请求保持:一次性申请所有资源
- 不可抢占:已经占用一部分资源的线程进一步申请其他资源的时候,如果申请不到,可以主动释放占有的资源
- 循环等待:按序申请资源
ThreadLocal
ThreadLocal有什么用
让每一个线程都有自己专属的本地变量,让每一个线程存储自己的私有数据