线程的上下文切换是从什么切换到什么

315 阅读5分钟

要了解一个东西究竟是什么,我一般会从这个东西有什么直观的体现,再到它是什么,怎么运转以及何时运转等扩展问题进行深入学习。

线程上下文切换直观体现

单核处理器能够支持多线程执行代码就是因为线程的上下文切换。

具体是如何做到的呢?

CPU通过给每个线程分配CPU时间片来实现这个机制。

什么是时间片?CPU分配给每个线程的时间。时间片非常短一般几十ms。

CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的。

什么是线程上下文切换

  1. 什么是上下文切换

把当前任务的状态保存下来,以便下次切换回这个任务时可以再次加载这个任务的状态,并加载下一任务的状态并执行。任务的状态保存及其再加载,这个过程就叫做上下文切换

  1. 什么是线程上下文切换

如果可运行的线程数大于CPU的数量,CPU利用时间片轮转的方式,可以使用户感觉这些任务正在同时进行。时间片用完或者被迫中止等情况就会发现另一个线程来执行CPU时间片。

  1. 什么是线程上下文

线程上下文是指某一时间点CPU寄存器和程序计数器的内容。

每个线程都有一个程序计数器、一组寄存器、堆栈。

  1. 程序计数器

记录要执行的下一条指令。是一个专用寄存器,用来表明指令序列中CPU正在执行的位置,存的值为正在执行的指令的位置或者下一个将要被执行的指令的位置。

  1. 寄存器

保存当前线程的工作变量。是CPU内部的数量较少但速度很快的内存。

  1. 堆栈

记录执行历史,其中每一帧保存了一个已经调用但未返回的过程。

线程上下文切换过程

  1. 挂起当前线程

将这个线程在CPU中的上下文/状态存储于内存中的某处。

  1. 恢复一个线程

在内存中检索下一个任务的上下文并将其在CPU的寄存器中恢复。

  1. 跳转到程序计数器所指向的位置/任务被中断时的代码行,以恢复该线程。

什么时候发生线程上下文切换

时间片用完或被迫终止的情况。

自发性上下文切换

主动放弃线程进程的运行机会,迫使CPU保存上下文。

  1. sleep
  2. wait
  3. yield 让出cpu
  4. join
  5. park
  6. synchronized
  7. lock
  8. mutex
  9. semaphore

非自发性上下文切换

中断或者任务调度会引发上下文切换;时间片用完属于非自发性上下文切换。

  1. 时间片用完(操作系统调度)
  2. gc的Stop the World阶段

上下文切换可能产生的问题与优化改进

产生性能问题 减少上下文切换

减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。

  1. JVM锁优化
  2. synchronized更小粒度锁
  3. CAS算法 Juc使用volatile+Cas机制。Volatile保证可见性和有序性,并不会引起上下文切换。Atomic包下的类使用CAS算法来更新数据不需要加锁。不会引起线程上下文切换。
  4. 使用最少线程数。更好的设置线程池大小避免创建不需要的线程,比如任务很少但创建了很多线程这样会造成大量线程都处于等待状态。
  5. 减少gc中的Stop The World
  6. 无锁并发编程 多线程竞争锁时会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段数据。
  7. 协程。在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。

怎样监控线程上下文

Windows下可使用Process Explorer软件。或者perfmon工具报告上下文切换次数以及在内核中执行时间所占比例等信息。

其他

  1. 上下文切换当前线程在CPU内的缓存怎么处理

  2. 为什么进程上下文切换比线程上下文切换代价高

进程切换需要多做一步页目录切换以使用新的地址空间。进程切换的虚拟内存空间是不相同的。

  1. 上下文切换到底切换了什么?(感觉等于在问上下文切换的流程

将前一个CPU寄存器和程序计数器里面的内容保存起来,加载新任务的上下文到寄存器和程序计数器。最后跳转到程序计数器所指的新位置运行新任务。 被保存起来的上下文会存储到系统内核中,等待任务重新调度执行时再次加载进来。

  1. 线程上下文切换保存了什么?

CPU寄存器和程序计数器。

始终觉得很多面试题就算看了再多资料也像是没搞明白,只是大概知道它是什么。先记录下来,如果以后成体系了,能真的理解了。再更新