单核处理器能够支持多线程执行代码就是因为线程的上下文切换。
具体是如何做到的呢?
CPU通过给每个线程分配CPU时间片来实现这个机制。
什么是时间片?CPU分配给每个线程的时间。时间片非常短一般几十ms。
CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的。
什么是线程上下文切换
什么是上下文切换
把当前任务的状态保存下来,以便下次切换回这个任务时可以再次加载这个任务的状态,并加载下一任务的状态并执行。任务的状态保存及其再加载,这个过程就叫做上下文切换。
什么是线程上下文切换
如果可运行的线程数大于CPU的数量,CPU利用时间片轮转的方式,可以使用户感觉这些任务正在同时进行。时间片用完或者被迫中止等情况就会发现另一个线程来执行CPU时间片。
什么是线程上下文
线程上下文是指某一时间点CPU寄存器和程序计数器的内容。
每个线程都有一个程序计数器、一组寄存器、堆栈。
- 程序计数器
记录要执行的下一条指令。是一个专用寄存器,用来表明指令序列中CPU正在执行的位置,存的值为正在执行的指令的位置或者下一个将要被执行的指令的位置。
- 寄存器
保存当前线程的工作变量。是CPU内部的数量较少但速度很快的内存。
- 堆栈
记录执行历史,其中每一帧保存了一个已经调用但未返回的过程。
线程上下文切换过程
- 挂起当前线程
将这个线程在CPU中的上下文/状态存储于内存中的某处。
- 恢复一个线程
在内存中检索下一个任务的上下文并将其在CPU的寄存器中恢复。
跳转到程序计数器所指向的位置/任务被中断时的代码行,以恢复该线程。
什么时候发生线程上下文切换
时间片用完或被迫终止的情况。
自发性上下文切换
主动放弃线程进程的运行机会,迫使CPU保存上下文。
- sleep
- wait
- yield
- 让出cpu
- join
- park
- synchronized
- lock
- mutex
- semaphore
非自发性上下文切换
中断或者任务调度会引发上下文切换;时间片用完属于非自发性上下文切换。
- 时间片用完(操作系统调度)
- gc的Stop the World阶段
上下文切换可能产生的问题与优化改进
产生性能问题 减少上下文切换
减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。
JVM锁优化
synchronized更小粒度锁
CAS算法
Juc使用volatile+Cas机制。Volatile保证可见性和有序性,并不会引起上下文切换。Atomic包下的类使用CAS算法来更新数据不需要加锁。不会引起线程上下文切换。
使用最少线程数。更好的设置线程池大小避免创建不需要的线程,比如任务很少但创建了很多线程这样会造成大量线程都处于等待状态。
减少gc中的Stop The World
无锁并发编程
多线程竞争锁时会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段数据。
协程。在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。
怎样监控线程上下文
Windows下可使用Process Explorer软件。或者perfmon工具报告上下文切换次数以及在内核中执行时间所占比例等信息。
其他
上下文切换当前线程在CPU内的缓存怎么处理
为什么进程上下文切换比线程上下文切换代价高
进程切换需要多做一步页目录切换以使用新的地址空间。进程切换的虚拟内存空间是不相同的。
上下文切换到底切换了什么?
将前一个CPU寄存器和程序计数器里面的内容保存起来,加载新任务的上下文到寄存器和程序计数器。最后跳转到程序计数器所指的新位置运行新任务。
被保存起来的上下文会存储到系统内核中,等待任务重新调度执行时再次加载进来。
线程上下文切换保存了什么?
CPU寄存器和程序计数器以及用户栈。
在UNIX系统中,线程(也称为轻量级进程)上下文切换是指操作系统在两个线程之间切换执行的过程。这种切换使得操作系统能够在多个线程之间共享CPU资源,实现并发执行。线程上下文切换比进程上下文切换要轻量,因为线程共享同一个进程的地址空间和资源,而进程各自拥有独立的地址空间和资源。
线程上下文包括:
CPU寄存器状态:包括程序计数器(PC)、堆栈指针(SP)、以及其他通用寄存器的当前值。
线程栈:每个线程有自己的栈,用于存储局部变量和跟踪函数调用。线程上下文切换时,需要保存和恢复线程栈的状态。
线程特定数据(TSD):与线程相关的特定数据,如线程ID和线程的状态信息。
调度信息:包括线程的优先级、调度策略和其他与调度相关的信息。
触发线程上下文切换的情况:
时间片耗尽:在时间片轮转调度中,当线程的时间片耗尽时,操作系统会切换到另一个线程执行。
I/O操作:当线程执行I/O操作并进入等待状态时,操作系统会切换到另一个就绪状态的线程。
线程终止:当线程完成执行并终止时,操作系统需要切换到另一个线程。
同步操作:当线程等待某个同步原语(如互斥锁、信号量)时,操作系统可能会切换到另一个线程。
高优先级线程就绪:当一个高优先级线程变为就绪状态时,操作系统可能会抢占当前线程,以便让高优先级线程执行。
线程上下文切换的开销:
尽管线程上下文切换比进程上下文切换开销小,但仍然有一定的开销,主要包括保存和恢复线程上下文的时间,以及由于切换导致的缓存失效等。操作系统设计者通常会尽量优化上下文切换的过程,以减少这些开销,提高系统的并发性能和响应速度。
在多线程编程中,合理地使用同步机制、避免不必要的线程切换和设计高效的线程调度策略是提高应用性能的关键。
标签:执行,操作系统,线程,切换,上下文,CPU From: https://www.cnblogs.com/DCFV/p/18442476