一、进程和线程
1.操作系统、进程、线程的关系
操作系统是包含多个进程的容器,而每个进程又是容纳多个线程的容器。
2.Oracle 官方定义
官方定义
进程:使用 fork(2) 系统调用创建的UNIX 环境(例如文件描述符,用户 ID 等),它被设置为运行程序。
线程:在进程上下文执行的一系列指令。
3.什么是进程
进程(Process)是程序的运行实例。
进程是程序向操作系统申请资源(如内存空间和文件句柄)的基本单位。
在用户下达运行程序的命令后,就会产生进程,任务管理器中的每一个应用都是一个进程。谷歌浏览器的每个标签页和插件都是一个进程。
4.什么是线程
线程是操作系统能够进行资源调度的最小单位,它被包含在进程之中,是进程中的实际运作单位,每个线程执行的都是进程代码的某个片段,特定的线程总是在执行特定的任务。
5.进程和线程的关系
5.1 起源不同
先有进程,后有线程。进程由于资源利用率、公平性和便利性诞生。处理器的速度往往比外设的速度快(键盘、鼠标等),为了提高 CPU 的利用率,诞生了线程,目的就是为了提高程序的执行效率。
5.2 概念不同
进程是资源分配的最小单位。
线程是程序执行的最小单位(线程是操作系统能够进行资源调度的最小单位,同个进程中的线程也可以被同时调度到多个 CPU 上运行),线程也被称为轻量级进程。
5.3 内存共享方式不同
默认情况下,进程的内存无法与其他进程共享(进程间通信通过 IPC 进行)。
线程共享由操作系统分配给其父进程的内存块。
5.4 拥有资源不同
操作系统为各个独立执行的进程分配各种资源,包括内存,文件句柄以及安全证书等。
线程会共享进程范围内的资源,例如内存句柄、文件句柄、进程用户 ID 以及进程组 ID 等。每个线程也有各自独立的资源,例如线程 ID、程序计数器、栈以及局部变量等。
5.5 数量不同
一个程序至少拥有一个进程,一个进程至少拥有一个线程。
5.6 开销不同
线程的创建、终止时间比进程短。
同一进程内的线程切换时间比进程短。
同一进程的各个线程间共享内存和文件资源,可以不通过内核进行通信。
5.7 生命周期类似
进程和线程都包含就绪、运行、等待状态。
6.Java 和多线程的关系
Java 在设计之初就支持了多线程,而且 Java 中的线程会一对一映射到操作系统的内核线程中(实际的线程数量,不是虚拟线程)。除了我们启动的线程,还包括 JVM 自启动线程。
二、多线程
1.什么是多线程
1.1 概念
多线程是指单个进程中运行多个线程,如果一个程序允许运行两个或以上的线程,那么它就是多线程程序。
1.2 例子
房间的例子客厅:公共空间厕所:锁独立房间:线程共享空间打扫卫生:线程合作
火锅的例子大火锅一个人吃:单进程单线程大火锅多个人吃:单进程多线程
2. 使用多线程的原因
2.1 发挥多核处理器的强大能力
充分发挥多核 CPU 的优势,提高处理器速度。
避免无效等待(进行 I/O 操作时可以处理其他事情)。
提升用户体验性,避免卡顿,缩短等待时间并行处理,提高性能,通常用于服务器(例如 Tomcat),用多个线程去处理接收的 HTTP 请求。在 Android 开发中,主线程的任务之一就是绘制屏幕, 主线程不允许进行IO 操作或网络请求,目的就是为了避免卡顿,影响用户的体验。
2.2 便于编程建模
将大的任务分割为多个小任务,分别建立程序模型,并通过多线程分别运行这几个任务。
2.3 计算机的性能定律
摩尔定律失效
摩尔定律——当价格不变时,集成电路上可容纳的元器件的数目每个 18-24 个月就会翻一倍以上,性能也会提升一倍。
阿姆达尔定律(Amdahl)登台
阿姆达尔定律:处理器越多,程序执行就越快,但有上限,取决于程序中串行部分的比例,并行的比例越高,多处理器的效果越明显。
最下面蓝色曲线,当并行的比例为 50% 时,最快速度可以提升2倍;最上面绿色曲线,当并行的比例为 95% 时,最快速度可以提升20倍。
3.多线程使用场景
后台线程,如执行定时任务。
tomcat——每次有一个新的请求过来的时候,tomcat 会把这个请求交给一个新的线程去处理。
多线程后台并行下载文件。
4.多线程的风险
4.1 安全性问题
当多个线程同时访问和修改相同的变量时,将会在串行编程模型中引入非串行因素,如 i++ 的数据错误。
4.2 活跃性问题
当某个操作无法继续执行下去的时候,就会发生活跃性问题,如死锁、饥饿以及活锁。
4.3 性能问题
在多线程程序中,当线程调度器临时挂起活跃线程并转而运行另一个线程时,就会频繁得出现上下文切换操作(Context Switch),这种操作会带来极大的开销:保存和恢复执行上下文,丢失局部性,并且 CPU 将更多的时间花在线程调度而不是线程运行上。当线程共享数据时,必须使用同步机制,而这些机制往往会抑制某些编译器优化,使内存缓冲区的数据无效,以及增加共享内存总线的同步流量。这些因素都将带来额外的性能开销。
三、串行、并行、并发
1.串行
串行是将多个任务按顺序排队执行,例如:听完音乐再写代码。
2.并行
真正的“同时”运行,在同一时刻有多个任务执行,需要多核处理器,因为单核处理器无法在同一时刻执行多个任务。例如:边听音乐边写代码。
3.并发
两个或多个任务可以在重叠时间段内启动,运行和完成。
并行(两个线程同时执行)一定是并发,并发并不一定是并行。
例如一会儿听音乐,一会儿写代码,轮流执行。
4.高并发
4.1 概念
同时有很多个请求发送给服务器系统,服务器并行处理请求。
4.2 多线程和高并发
高并发是一种状态,多线程是高并发的一种重要解决方案,高并发并不意味着多线程。
4.3 高并发指标
QPS(Queries Per Second)
带宽
PV (Page View)
UV(Unique Visitor)
吞吐率(Requests Per Second)
并发连接数(The number of concurrent connections)
服务器平均请求等待时间(Time per request: across all concurrent requests)
五、同步、异步、阻塞、非阻塞
1.同步与异步
同步和异步关注的是消息通信机制,这里指的是调用者的行为,表示请求是串行还是并行。
同步(Synchronous):客户端发出一个请求后,一直等到服务端返回最终的结果。
异步(Asynchronous):客户端发出一个请求后,还可以发出另外的请求,不用等待之前请求的结果返回。
2.阻塞与非阻塞
阻塞非阻塞关注的程序在等待调用结果(消息,返回值)时的状态,强调状态。
阻塞:客户端发起一个请求后,当前线程会被挂起,直到服务端返回结果。
非阻塞:客户端发起一个请求后,不管服务器会不会立刻返回结果,当前线程都不会被挂起。
3.例子
水壶烧水的例子,有两种水壶,一种普通水壶,只能自己观察水是否烧开;一种带提醒的水壶,水烧开会有声音提醒。
同步阻塞:用普通水壶烧水,一直等着该水壶的水烧开。
同步非阻塞:用普通水壶烧水,然后去客厅看电视,时不时观察水烧开了没。
异步阻塞:用带提醒的水壶烧水,一直等着该水壶的水烧开。
异步非阻塞:用带提醒的水壶烧水,然后去玩手机,直到该水壶发出声音提醒。