第三章 线程
3.1 线程的基本概念
1.什么是线程?为什么要引入线程?
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。引入线程的原因包括:
提高并发性:线程可以独立执行,使得一个程序可以同时执行多个任务,提高程序的并发性能。
资源共享:同一进程内的线程共享进程的资源,如内存和文件描述符,这减少了资源管理的开销。
响应性:线程的创建、切换和销毁比进程更快,可以提供更快的响应时间。
简化编程模型:线程简化了并发编程的模型,使得程序设计更加模块化。
2.引入线程机制后,有什么变化?
资源管理:线程共享进程资源,减少了资源分配和管理的复杂性。
调度:线程的调度通常比进程调度更加频繁,操作系统需要更高效的调度算法。
同步:线程间的同步和通信机制需要更加精细,以避免竞态条件和死锁。
上下文切换:线程的上下文切换比进程的上下文切换开销小。
**调度单位:**线程是一个基本的CPU执行单元,也是程序执行流的最小单位。进程只作为除CPU之外的系统资源的分配单位。(如打印机,内存地址空间等)
3.线程有哪些重要的属性?
线程ID:唯一标识一个线程。
程序计数器:记录下一条要执行的指令。
寄存器集合:保存线程的当前工作状态。
堆栈:用于存放局部变量和执行函数调用。
状态:线程可以处于不同的状态,如新建、就绪、运行、阻塞、终止等。
3.2 线程的实现方式和多线程模型
1.线程的实现方式
用户级线程(User-Level Threads,ULTs):
由用户空间的线程库管理,不依赖于操作系统的内核。
调度算法由线程库实现。
上下文切换快,不涉及内核态与用户态的切换。
内核级线程(Kernel-Level Threads,KLTs):
由操作系统内核管理。
调度由操作系统负责。
可以利用多处理器,但上下文切换开销较大。
2.多线程模型
多对一模型(Many-to-One):
多个用户级线程映射到一个内核级线程。
优点是线程管理简单,上下文切换快。
缺点是如果一个线程执行系统调用阻塞,整个进程都会被阻塞。
一对一模型(One-to-One):
每个用户级线程映射到一个内核级线程。
可以利用多处理器,一个线程的阻塞不会影响其他线程。
缺点是创建和管理的开销大。
多对多模型(Many-to-Many):
多个用户级线程映射到多个内核级线程。
结合了多对一和一对一的优点,提供了更好的并发性和响应性。
管理复杂,需要线程库和内核之间良好的协作。
线程和多线程模型的选择取决于应用程序的需求、目标平台和操作系统的支持。
3.3 线程的状态与转换
线程的状态与转换
线程在其生命周期内可以处于以下几种状态,并且可以在一定条件下相互转换:
新建(New):
状态描述:当使用 new 关键字创建一个线程后,直到调用 start() 方法之前,线程处于新建状态。
转换条件:调用 start() 方法。
就绪(Runnable):
状态描述:线程调用 start() 方法后,进入就绪状态。就绪状态的线程位于可运行池中,等待被线程调度器选中获取CPU的执行时间。
转换条件:线程调度器选中该线程。
运行(Running):
状态描述:线程获得CPU时间,执行程序代码。
转换条件:时间片用完;更高优先级的线程需要运行;线程自己调用 yield() 方法;线程被调度器终止。
阻塞(Blocked):
状态描述:线程因为某些原因放弃CPU,暂时停止运行。阻塞状态是线程阻塞在进入同步代码块/方法或等待某个条件发生。
转换条件:获取锁;等待的条件成立。
等待(Waiting):
状态描述:线程等待其他线程执行特定操作(通知)。
转换条件:其他线程发出通知。
超时等待(Timed Waiting):
状态描述:线程在一定时间内等待另一个线程的通知。
转换条件:时间到达;其他线程发出通知。
终止(Terminated):
状态描述:线程的 run() 方法执行完成,或者线程调用了 stop() 方法,或者因为一个未捕获的异常导致线程终止。
转换条件:线程执行结束。
线程的组织与控制
线程的组织与控制主要涉及以下几个方面:
线程控制块(TCP):
线程标识符:TID
程序计数器PC:线程目前执行到哪里
其他寄存器:线程运行的中间结果
堆栈指针:堆栈保存函数调用信息,局部变量等
线程运行状态:运行/就绪/阻塞
优先级:线程调度,资源分配参考
线程的创建:
继承 Thread 类并重写 run() 方法。
实现 Runnable 接口的 run() 方法。
使用 Executor 框架创建线程池。
线程的调度:
分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,Java 默认采用抢占式调度。
线程的控制:
线程睡眠:Thread.sleep(long millis),让线程暂停执行指定的时间。
线程让步:Thread.yield(),暂停当前正在执行的线程对象,并执行其他线程。
线程加入:join(),等待其他线程终止。
线程中断:interrupt(),中断线程的阻塞状态。
线程同步:
使用 synchronized 关键字实现同步方法或同步代码块。
使用 Lock 显示锁控制临界区。
线程通信:
使用 Object 类的 wait()、notify()、notifyAll() 方法进行线程通信。
线程池管理:
通过 Executors 工厂类创建不同类型的线程池。
使用 ThreadPoolExecutor 自定义线程池。
线程的正确使用和管理对于提高程序的性能和稳定性至关重要。在多线程编程中,需要注意线程安全、资源共享和合理利用系统资源。
Last updated