由于现在大多计算机都是多核CPU,多线程往往会比单线程更快,更能够提高并发,但提高并发并不意味着启动更多的线程来执行。更多的线程意味着线程创建销毁开销加大、上下文非常频繁,你的程序反而不能支持更高的TPS。可以看另一篇《Java从线程安全到synchronized和Lock探索》

时间片

多任务系统往往需要同时执行多道作业。作业数往往大于机器的CPU数,然而一颗CPU同时只能执行一项任务,如何让用户感觉这些任务正在同时进行呢? 操作系统的设计者 巧妙地利用了时间片轮转的方式

时间片是CPU分配给各个任务(线程)的时间!

思考:单核CPU为何也支持多线程呢?

线程上下文是指某一时间点 CPU 寄存器和程序计数器的内容,CPU通过时间片分配算法来循环执行任务(线程),因为时间片非常短,所以CPU通过不停地切换线程执行。

换言之,单CPU这么频繁,多核CPU一定程度上可以减少上下文切换。

超线程

现代CPU除了处理器核心之外还包括寄存器、L1L2缓存这些存储设备、浮点运算单元、整数运算单元等一些辅助运算设备以及内部总线等。一个多核的CPU也就是一个CPU上有多个处理器核心,就意味着程序的不同线程需要经常在CPU之间的外部总线上通信,同时还要处理不同CPU之间不同缓存导致数据不一致的问题。

超线程这个概念是Intel提出的,简单来说是在一个CPU上真正的并发两个线程,由于CPU都是分时的(如果两个线程A和B,A正在使用处理器核心,B正在使用缓存或者其他设备,那AB两个线程就可以并发执行,但是如果AB都在访问同一个设备,那就只能等前一个线程执行完后一个线程才能执行)。实现这种并发的原理是 在CPU里加了一个协调辅助核心,根据Intel提供的数据,这样一个设备会使得设备面积增大5%,但是性能提高15%~30%。

上下文切换

  • 线程切换,同一进程中的两个线程之间的切换
  • 进程切换,两个进程之间的切换
  • 模式切换,在给定线程中,用户模式和内核模式的切换
  • 地址空间切换,将虚拟内存切换到物理内存

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

每个线程都有一个程序计数器(记录要执行的下一条指令),一组寄存器(保存当前线程的工作变量),堆栈(记录执行历史,其中每一帧保存了一个已经调用但未返回的过程)。

寄存器 是 CPU 内部的数量较少但是速度很快的内存(与之对应的是 CPU 外部相对较慢的 RAM 主内存)。寄存器通过对常用值(通常是运算的中间值)的快速访问来提高计算机程序运行的速度。

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

  1. 挂起当前任务(线程/进程),将这个任务在 CPU 中的状态(上下文)存储于内存中的某处
  2. 恢复一个任务(线程/进程),在内存中检索下一个任务的上下文并将其在 CPU 的寄存器中恢复
  3. 跳转到程序计数器所指向的位置(即跳转到任务被中断时的代码行),以恢复该进程在程序中

线程上下文切换会有什么问题呢?

上下文切换会导致额外的开销,常常表现为高并发执行时速度会慢串行,因此减少上下文切换次数便可以提高多线程程序的运行效率。

  • 直接消耗:指的是CPU寄存器需要保存和加载, 系统调度器的代码需要执行, TLB实例需要重新加载, CPU 的pipeline需要刷掉
  • 间接消耗:指的是多核的cache之间得共享数据, 间接消耗对于程序的影响要看线程工作区操作数据的大小

切换查看

Linux系统下可以使用vmstat命令来查看上下文切换的次数, 其中cs列就是指上下文切换的数目一般情况下, 空闲系统的上下文切换每秒大概在1500以下

线程调度

抢占式调度

指的是每条线程执行的时间、线程的切换都由系统控制,系统控制指的是在系统某种运行机制下,可能每条线程都分同样的执行时间片,也可能是某些线程执行的时间片较长,甚至某些线程得不到执行的时间片。在这种机制下,一个线程的堵塞不会导致整个进程堵塞。

java使用的线程调使用抢占式调度,Java中线程会按优先级分配CPU时间片运行,且优先级越高越优先执行,但优先级高并不代表能独自占用执行时间片,可能是优先级高得到越多的执行时间片,反之,优先级低的分到的执行时间少但不会分配不到执行时间。

协同式调度

指某一线程执行完后主动通知系统切换到另一线程上执行,这种模式就像接力赛一样,一个人跑完自己的路程就把接力棒交接给下一个人,下个人继续往下跑。线程的执行时间由线程本身控制,线程切换可以预知,不存在多线程同步问题,但它有一个致命弱点:如果一个线程编写有问题,运行到一半就一直堵塞,那么可能导致整个系统崩溃。

线程让出cpu的情况

  • 当前运行线程主动放弃CPU,JVM暂时放弃CPU操作(基于时间片轮转调度的JVM操作系统不会让线程永久放弃CPU,或者说放弃本次时间片的执行权),例如调用yield()方法。
  • 当前运行线程因为某些原因进入阻塞状态,例如阻塞在I/O上
  • 当前运行线程结束,即运行完run()方法里面的任务

引起线程上下文切换的因素

  • 当前执行任务(线程)的时间片用完之后,系统CPU正常调度下一个任务
  • 中断处理,在中断处理中,其他程序”打断”了当前正在运行的程序。当CPU接收到中断请求时,会在正在运行的程序和发起中断请求的程序之间进行一次上下文切换。中断分为硬件中断和软件中断,软件中断包括因为IO阻塞、未抢到资源或者用户代码等原因,线程被挂起。
  • 用户态切换,对于一些操作系统,当进行用户态切换时也会进行一次上下文切换,虽然这不是必须的。
  • 多个任务抢占锁资源,在多任务处理中,CPU会在不同程序之间来回切换,每个程序都有相应的处理时间片,CPU在两个时间片的间隔中进行上下文切换

因此优化手段有:

  • 无锁并发编程,多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash取模分段,不同的线程处理不同段的数据
  • CAS算法,Java的Atomic包使用CAS算法来更新数据,而不需要加锁
  • 使用最少线程
  • 协程,单线程里实现多任务的调度,并在单线程里维持多个任务间的切换

合理设置线程数目既可以最大化利用CPU,又可以减少线程切换的开销。

  • 高并发,低耗时的情况,建议少线程。
  • 低并发,高耗时的情况:建议多线程。
  • 高并发高耗时,要分析任务类型、增加排队、加大线程数

基本功:线程上下文切换相关推荐

  1. cpu线程_进程/线程上下文切换会用掉你多少CPU?

    进程是操作系统的伟大发明之一,对应用程序屏蔽了CPU调度.内存管理等硬件细节,而抽象出一个进程的概念,让应用程序专心于实现自己的业务逻辑既可,而且在有限的CPU上可以"同时"进行许 ...

  2. 关于线程上下文切换,你知道多少?

    点击关注公众号,实用技术文章及时了解 由于现在大多计算机都是多核CPU,多线程往往会比单线程更快,更能够提高并发,但提高并发并不意味着启动更多的线程来执行.更多的线程意味着线程创建销毁开销加大.上下文 ...

  3. 图文上下切换代码_Java核心知识 多线程并发 线程上下文切换(二十一)

    巧妙地利用了时间片轮转的方式, CPU 给每个任务都服务一定的时间,然后把当前任务的状态保存 下来,在加载下一任务的状态后,继续服务下一任务,任务的状态保存及再加载, 这段过程就叫做 上下文切换.时间 ...

  4. 进程和线程上下文切换

    图文对比 进程上下文切换 进程上下文包含了进程执行所需要的所有信息. 1.用户地址空间:包括程序代码,数据,用户堆栈等: 2.控制信息:进程描述符,内核栈等: 3.硬件上下文:进程恢复前,必须装入寄存 ...

  5. 进程和线程上下文切换_编码人员:上下文切换对于计算机和关系而言都很难

    进程和线程上下文切换 Clive Thompson is a longtime contributing writer for the New York Times Magazine and a co ...

  6. mysql 上下文切换高_进程/线程上下文切换会用掉你多少CPU?

    进程是操作系统的伟大发明之一,对应用程序屏蔽了CPU调度.内存管理等硬件细节,而抽象出一个进程的概念,让应用程序专心于实现自己的业务逻辑既可,而且在有限的CPU上可以"同时"进行许 ...

  7. Java线程上下文切换

    0 前言 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的"同一时间点",而是 多个 ...

  8. CPU分析系列--vmstat/pidstat -wt分析进程/线程上下文切换造成的性能瓶颈

    目录 1.从系统层面看:vmstat 1 3 2.从进程层面看:pidstat -w 3.从线程层面看上下文切换:pidstat -wt 4.案例: 1.使用sysbench模拟多线程切换. yum ...

  9. 一篇文章带你「重新认识」线程上下文切换怎么玩儿

    调度 当一个计算机是多道程序设计系统时,会频繁的有很多进程或者线程来同时竞争 CPU 时间片.当两个或两个以上的进程/线程处于就绪状态时,就会发生这种情况.如果只有一个 CPU 可用,那么必须选择接下 ...

最新文章

  1. 这6种最常见分布式事务解决方案!请拿走不谢!
  2. mySQL优化 my.ini 配置说明
  3. java越权发送邮件_已登录用户 越权 访问action方法怎么解决?
  4. 数据分析sql面试必会6题经典_师兄大厂面试遇到这条 SQL 数据分析题,差点含泪而归!...
  5. [转] FFmpeg常用基本命令
  6. golang mysql scan_在Golang中对MySQL进行操作
  7. mysql 忘记 root 密码
  8. 快速切换Mac系统设置One Switch
  9. 在Eclipse中使用Gradle开发web3j以太坊应用
  10. directx9又更新了。
  11. 首次在matable中安装libsvm碰到的问题和解决方法---- mxGetIr 已过时 错误
  12. 华为大数据解决方案 (文末附PPT下载)
  13. Ajax不执行回调函数
  14. 非计软专业的学生也能看懂的面向对象编程(《面向对象编程是怎样工作的》平野章/著 读书笔记)
  15. java isbn_ISBN书号查询示例代码
  16. opencv图像对比度
  17. Opencv求轮廓的中心点坐标
  18. 【原创】基于SpringBoot的同城生鲜门店配送系统(SpringBoot配送系统毕业设计)
  19. 弘辽科技:淘宝提升销量怎么越提升越没流量?是什么原因?
  20. 2021年专插本计算机专业分数线预估,【参考】2016-2020年专插本省最低录取控制线预估2021年最低录取分数线是多少...

热门文章

  1. VS2015报错C4996处理
  2. Debian11安装搜狗输入法
  3. 有限体积法(9)——高阶差分格式:QUICK格式
  4. 微信小程序中页面引入js文件
  5. java通过jstack命令查询日志深入理解
  6. PHP error_reporting
  7. Vue联动下拉框默认选中
  8. CSDN cdsn显示发布频繁 请稍后重试 和保存草稿不成功 的解决办法
  9. (三十)arcpy开发pycharm导入arcpy
  10. velocity 将字符串切割按每隔3位加逗号,map集合遍历,字符串拼接,