【Java并发编程篇】Java线程的上下文切换与线程状态

上下文切换

在并发编程中,并不是线程越多就效率越高,线程数太少可能导致资源不能充分利用,线程数太多可能导致竞争资源激烈,然后上下文切换频繁造成系统的额外开销。那什么是上下文切换呢?

什么是上下文切换?

在处理多线程并发任务时,处理器会给每个线程分配CPU时间片,线程在各自分配的时间片内占用处理器并执行任务,当线程的时间片用完了,或者自身原因被迫暂停运行的时候,就会有另外一个线程来占用这个处理器,这种一个线程让出处理器使用权,另外一个线程获取处理器使用权的过程就叫做上下文切换。

一个线程让出CPU处理器使用权,就是“切出”;另外一个线程获取CPU处理器使用权。就是“切入”,在这个切入切出的过程中,操作系统会保存和恢复相关的进度信息,而这个进度信息就是我们常说的“上下文”,上下文一般包含了寄存器的存储内容以及程序计数器存储的指令内容。

对于单核单线程 CPU 而言,在某一时刻只能执行一条 CPU 指令。从用户角度看,计算机能够并行运行多个进程,这恰恰是操作系统通过快速上下文切换造成的结果。每个时间片的大小一般为几十毫秒,所以在一秒钟就可能发生几十上百次的线程相互切换,给我们的感觉就是同时进行的

Java 多线程的上下文切换

在 Java 中,多线程的上下文切换就是多线程两个运行状态的相互切换导致的。在切换时操作系统保存上下文信息,当线程从 BLOCKED 状态进入到 RUNNABLE 时,也就是线程的唤醒,此时线程将获取上次保存的上下文信息,接着之前的进度继续执行。

在 Java 中,两种情况会导致上下文切换:一种是自发性上下文切换,也就是程序本身触发的切换;另一种是非自发性上下文切换,也就是系统或者虚拟机导致的上下文切换。

(1)自发性上下文是线程由 Java 程序调用导致切出,一般是在编码的时候,调用以下几个方法或关键字:

sleep()、wait()、yield()、join()、park()、synchronized、lock

(2)非自发的上下文切换常见的有:线程被分配的时间片用完,虚拟机垃圾回收导致,或者执行优先级的问题导致

上下文切换的系统开销

  • 操作系统保存和恢复上下文
  • 处理器高速缓存加载
  • 调度器进行调度
  • 上下文切换可能导致的高速缓冲区被冲刷

小结

上下文切换就是一个线程释放处理器的使用权,另外一个线程获取处理器的使用权的过程;在切入切出时,系统会保存和读取当前线程的上下文信息,用户恢复线程的执行进度;自发和非自发的调用操作,都会导致上下文切换,会导致系统资源开销。

线程越多不一定执行的速度越快,在单个逻辑比较简单的时候,而且速度相对来说非常快的情况下,我们推荐是使用单线程。如果逻辑非常复杂,或者需要进行大量的计算的地方,我们建议使用多线程来提高系统的性能。

 

参考:

 

posted @ 2021-12-21 22:34  残城碎梦  阅读(523)  评论(0编辑  收藏  举报