六、线程
6.1 线程的引入
引入理由
- 应用的需要
- 开销的考虑
- 性能的考虑
6.1.1 应用的需要
我们看一个例子,一个
web
服务器的工作方式
- 从客户端接收网页请求
- 从磁盘上检索相关的网页,读入内存(此时进程是停止的,直到读取完毕)
- 将网页返回给对应的客户端
可以看到每次从磁盘读取的时候进程都是暂停的,这样会导致性能低下
那如何提高服务器的工作效率?通常情况下是使用网页缓存
在
没有线程情况下的两种解决方案
- 一个服务进程undefined这种情况下也是一种顺序编程,虽然采用了缓存机制,但是性能同样不高。而如果设置多个进程,这多个进程之间又是相互独立的,有独立的地址空间,所以不能共享信息
- 有限状态机undefined这种方式编程模型复杂,采用非阻塞的
I/O
多线程的解决方式

**说明:**这是一个多线程的
web
服务器的工作方式,首先读取客户端的请求,之后由分派线程将各个任务分派给工作线程,这里还是采用了网页缓存
于是我们可以看到一个
web
服务器的实现有三种方式:
6.1.2 开销的考虑
6.1.3 性能的考虑
如果有多个处理器的话,一个进程就会有多个线程同时在执行了,这样可以极大的提高运行性能
6.2 线程的基本概念
线程的属性
- 有标识符
ID
- 有状态及状态转换
需要提供一些操作-->
- 不运行时需要保存的上下文(程序计数器等寄存器)
- 有自己的栈和栈指针
- 共享所在进程的地址空间和其他资源
- 创建、撤销另一个线程(程序开始是以一个单线程方式运行的)
6.3 线程机制的实现
一般有三种实现机制
- 用户级线程
- 核心级线程
- 混合(两者结合)方法6.3.1 用户级线程
说明:线程是由运行时系统管理的,在内核中只有进程表。典型例子就是
UNIX
undefinedPOSIX线程库–PTHREAD
优点
- 线程切换快
- 调度算法是应用程序特定的
- 用户级线程可运行在任何操作系统上(只需要实现线程库)
缺点
- 内核只将处理器分配给进程,同一进程中的两个线程不能同时运行于两个处理器上
- 大多数系统调用是阻塞的,因此,由于内核阻塞进程,故进程中所有线程也被阻塞。(可以在调用之前判断进行解决,如果是阻塞线程,那么就换其他线程)6.3.2 核心级线程
- 线程创建在用户空间完成
- 线程调度等在核心态完成
- 例子如
操作系统Solaris
6.4 线程状态(Java)
0)新建:创建后尚未启动的线程处于这种状态。
1)运行:包括了 OS 中 Running 和 Ready 状态,也就是处于此状态的线程可能正在运行,也可能正在等待 cpu 为它分配执行时间
2)无限期等待:处于这种状态的线程不会被分配 cpu 执行时间,要等待其他线程显示唤醒。以下方法会让线程进入无限期等待 :
- 没有设置 timeout 的 object.wait()
- 没有设置 timeout 参数的 Thread.join()
- LockSupport.park()
3)有限期的等待:处于这种状态的线程也不会被分配 cpu 执行时间,不过无需等待被其他线程显示唤醒,而是在一定时间后,他们会由 OS 自动唤醒 1.设置了 timeout 的 object.wait() 方法 2. 设置了 timeout 参数的 Thread.join() 3.LockSupport.parkNanos()
4.LockSupport.parkUnit()
4) 阻塞:与"等待"的区别:
- 阻塞态在等待获取一个排它锁,这个事件将在另外一个线程放弃这个锁的时候发生
- 等待状态在等待一段时间或者唤醒动作。
5)结束:已终止线程的线程状态,线程已经结束执行。 进程的通信类型
- 共享存储器、管道、客户机-服务器系统(socket)
- 直接通信、间接通信(信箱)