一、基本概念介绍
1.1 多线程作用
为了更好的利用cpu的资源,以期望提高程序执行效率。
IO 操作不占用 cpu,只是我们一般拷贝文件使用的是【阻塞 IO】,这时相当于线程虽然不用 cpu,但需要一直等待 IO 结束,没能充分利用线程。所以才有后面的【非阻塞 IO】和【异步 IO】优化
1.2 并行与并发
并发:一个核快速切换多个线程,让它们依次执行,看起来像并行,实际上是并发。
并行:同一时间多个线程同时执行。【系统要有多个CPU才会出现并行】
并行在多处理器系统中存在,而并发可以在单处理器和多处理器系统中都存在。
高并发定义:高并发通常指的是单位时间内服务器处理很多的请求。
1.3 同步/异步、阻塞/非阻塞
一般的概念解释如下:
(1)同步/异步是站在调用方角度来讲:
- 如果需要等待结果返回,才能继续运行就是同步
- 不需要等待结果返回,就能继续运行就是异步
(2)阻塞/非阻塞是站在被调用方角度来讲:
- 等待有值时才返回,就是阻塞
- 被调用后立即返回值,就是非阻塞。 返回的可以是完整的结果, 也可以是不完整的结果, 还可以是一个空值。
另外的一种解释:(参考:同步/异步,阻塞/非阻塞概念深度解析_萧萧的专栏-CSDN博客_阻塞)
阻塞/非阻塞, 同步/异步的概念要注意讨论的上下文:
(1)在进程通信层面, 阻塞/非阻塞, 同步/异步基本是同义词。
(2)在 IO 系统调用层面, 非阻塞IO 系统调用 和 异步IO 系统调用存在着一定的差别, 它们都不会阻塞进程, 但是返回结果的方式和内容有所差别, 但是都属于非阻塞系统调用
( non-blocing system call )非阻塞I/O 系统调用( nonblocking system call ) 和 异步I/O系统调用 (asychronous system call)的区别:
一个非阻塞I/O 系统调用 read() 操作立即返回的是任何可以立即拿到的数据, 可以是完整的结果, 也可以是不完整的结果, 还可以是一个空值。而异步I/O系统调用 read()结果必须是完整的, 但是这个操作完成的通知可以延迟到将来的一个时间点。
1.4 进程与线程区别联系
联系:进程基本上相互独立的,而线程存在于进程内,是进程的一个子集。
区别:
(1)创建开销:系统创建进程需要为该进程重新分配系统资源,而创建线程代价比较小。参考:https://zhuanlan.zhihu.com/p/226174989
(2)切换开销:线程切换开销,比进程切换开销要小。
(3)共享内存:进程之间不能共享数据,线程可以。
(4)通信:
- 进程间通信较为复杂:
(a)同一台计算机的进程通信称为 IPC(Inter-process communication)
(b)不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如 HTTP
- 线程通信相对简单:synchronized--wait/notify、lock--await/signal、unsafe--park/unpark
进程用于申请资源,如内存、IO、网络资源,线程是对进程申请的资源进行共享
1.5线程切换
因为以下一些原因导致 cpu 不再执行当前的线程,转而执行另一个线程的代码叫线程切换(Thread Context Switch)。
常见的导致线程切换的场景:
- 线程的 cpu 时间片用完
- 线程阻塞(例如运行线程自己调用了 sleep、yield、wait、join、park、synchronized、lock 等方法)
- 垃圾回收
- 有更高优先级的线程需要
当 Context Switch 发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态。线程状态包括:
(1)程序计数器-->作用是记住下一条 jvm 指令的执行地址
(2)虚拟机栈中每个栈帧的信息-->如局部变量、操作数栈、返回地址等
Context Switch 频繁发生会影响性能