Java 性能调优实战
刘超
前金山软件技术经理
59174 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
开篇词 (1讲)
模块一 · 概述 (2讲)
结束语 (1讲)
Java 性能调优实战
15
15
1.0x
00:00/00:00
登录|注册

15 | 多线程调优(上):哪些操作导致了上下文切换?

垃圾回收导致的上下文切换
原因
触发方式
上下文内容
切出和切入
Synchronized导致的进程间上下文切换
何时使用单线程和多线程
上下文切换的影响
系统开销环节
监测上下文切换
上下文切换的性能问题
非自发性上下文切换
自发性上下文切换
线程状态转换
线程生命周期状态
上下文切换过程
CPU 时间片和线程切换
单个处理器时期的多线程并发任务处理
思考题
总结
发现上下文切换
多线程上下文切换诱因
初识上下文切换
哪些操作导致了多线程上下文切换?

该思维导图由 AI 生成,仅供参考

你好,我是刘超。
我们常说“实践是检验真理的唯一标准”,这句话不光在社会发展中可行,在技术学习中也同样适用。
记得我刚入职上家公司的时候,恰好赶上了一次抢购活动。这是系统重构上线后经历的第一次高并发考验,如期出现了大量超时报警,不过比我预料的要好一点,起码没有挂掉重启。
通过工具分析,我发现 cs(上下文切换每秒次数)指标已经接近了 60w ,平时的话最高 5w。再通过日志分析,我发现了大量带有 wait() 的 Exception,由此初步怀疑是大量线程处理不及时导致的,进一步锁定问题是连接池大小设置不合理。后来我就模拟了生产环境配置,对连接数压测进行调节,降低最大线程数,最后系统的性能就上去了。
从实践中总结经验,我知道了在并发程序中,并不是启动更多的线程就能让程序最大限度地并发执行。线程数量设置太小,会导致程序不能充分地利用系统资源;线程数量设置太大,又可能带来资源的过度竞争,导致上下文切换带来额外的系统开销。
你看,其实很多经验就是这么一点点积累的。那么今天,我就想和你分享下“上下文切换”的相关内容,希望也能让你有所收获。

初识上下文切换

我们首先得明白,上下文切换到底是什么。
其实在单个处理器的时期,操作系统就能处理多线程并发任务。处理器给每个线程分配 CPU 时间片(Time Slice),线程在分配获得的时间片内执行任务。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了多线程上下文切换的原因和影响。作者首先介绍了上下文切换的概念,并指出在多核处理器时代,上下文切换变得更加频繁,存在跨核切换更加昂贵。文章详细分析了多线程上下文切换的诱因,包括自发性和非自发性上下文切换,以及虚拟机垃圾回收可能导致的上下文切换。通过代码对比和数据分析,阐述了上下文切换对系统性能的影响,强调了单线程在某些情况下的优势。此外,还介绍了在Linux和Windows系统下监测上下文切换的方法,并总结了上下文切换可能带来的系统开销。最后,提出了思考题,引发读者对多线程中使用Synchronized可能导致的进程间上下文切换的思考。 总的来说,本文通过实例和技术原理深入浅出地介绍了多线程上下文切换的相关内容,对于理解并发编程中的性能问题具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 性能调优实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(48)

  • 最新
  • 精选
  • 晓杰
    锁的竞争太激烈会导致锁升级为重量级锁,未抢到锁的线程会进入monitor,而monitor依赖于底层操作系统的mutex lock,获取锁时会发生用户态和内核态之间的切换,所以会发生进程间的上下文切换。

    作者回复: 对的

    2019-06-25
    86
  • 尔冬橙
    老师,网上有个争议,sleep会不会释放cpu时间片?

    作者回复: sleep不会释放锁资源,wait则会,但两者都会从running状态中走出,也就是不再占用CPU资源。

    2019-09-20
    36
  • 李博
    如果Synchronized块中包含io操作或者大量的内存分配时,可能会导致进程IO等待或者内存不足。进一步会导致操作系统进行进程切换,等待系统资源满足时在切换到当前进程。 不知道理解的对不对?

    作者回复: 进程上下文切换,是指用户态和内核态的来回切换。我们知道,如果一旦Synchronized锁资源竞争激烈,线程将会被阻塞,阻塞的线程将会从用户态调用内核态,尝试获取mutex,这个过程就是进程上下文切换。

    2019-06-22
    3
    28
  • 内卷毁灭世界
    进程的上下文切换是指从一个进程切换到另一个进程运行。用户态到内核态为什么也属于进程上下文切换?从哪个进程切换到哪个进程了?

    作者回复: 在linux操作系统中,进程的运行空间一般分为用户态和内核态,用户态空间一般是进程应用运行空间,而内核态空间一般是指应用需要调用系统资源,应用不能再用户态空间直接调用系统资源,需要通过内核态来系统系统资源。 所以进程在用户态和内核态两个直接相互切换,就称之为进程上下文切换。

    2019-11-25
    17
  • 课后思考及问题 本文核心观点 1:线程上下文切换指啥? 线程上下文切换指一个线程被暂停剥夺对CPU的使用权,另外一个线程被选中开始或者继续在CPU中运行的过程。 2:线程上文切换的问题? 上下文切换会导致额外的性能开销,因为一个线程正在CPU上执行需要停下来换另外一个线程来执行,需要做许多的事情。 3:上下文切换的性能开销花费在哪里啦? 操作系统保存和恢复上下文; 调度器进行线程调度; 处理器高速缓存重新加载; 上下文切换也可能导致整个高速缓存区被冲刷,从而带来时间开销。 4:上下文切换的分类? 上下文切换分为进程上下文切换和线程上下文切换,这是站在操作系统的层面来讲的,站在CPU的角度,它不知道什么进程、线程之类的东西,他只需要知道怎么取指令怎么执行就行啦! 5:上下文切换的发送场景? 上下文切换分为两种,一是自发上下文切换,另一个是非自己上下文切换。 6:啥是自发上下文切换?怎么触发? 自发性上下文切换指线程由 Java 程序调用导致切出,在多线程编程中,执行调用以下方法或关键字,常常就会引发自发性上下文切换。 sleep() wait() yield() join() park() synchronized lock 7:啥是非自发上下文切换?怎么触发? 非自发性上下文切换指线程由于调度器的原因被迫切出。常见的有:线程被分配的时间片用完,虚拟机垃圾回收导致或者执行优先级的问题导致。 8:在多线程中使用 Synchronized 会发生进程间的上下文切换,具体的发生环节如下(声明:答案我没想到,参考评论区老师的回答)? 当升级到重量级锁后,线程竞争锁资源,将会进入等待队列中,并在等待队列中不断尝试获取锁资源。每次去获取锁资源,都需要通过系统调底层操作系统申请获取Mutex Lock,这个过程就是一次用户态和内核态的切换。 有个疑问,老师具体没讲什么是进程的上下文切换?什么是线程的上下文切换?评论区中又特意强调进程间的上下文切换指用户态和内核态之间的切换。那线程间的切换指什么?线程一直在内核态空间中,只是切出了CPU是吗?

    作者回复: 进程间的上下文切换因为是用户态和内核态之间的切换,需要消耗更多的资源,例如,寄存器中的内容切换出,缓存的刷新等,而线程间的上下文切换是用户态的线程切换,由于是同一个虚拟内存,消耗资源相对较少。

    2019-09-09
    12
  • 老杨同志
    使用Synchronized获得锁失败,进入等待队列会发生上下文切换。如果竞争锁时锁是其他线程的偏向锁,需要降级,这是需要stop the world也会发生上下文切换

    作者回复: 理解正确~

    2019-06-22
    3
    10
  • 尔冬橙
    老师,可以讲下进程从用户态到内核态为什么就发生了上下问切换呢

    作者回复: Java应用进程里面执行的代码则是属于用户态,而系统内核代码执行则属于内核态,假设我们一个同步锁的执行,首先会在Java应用程序中执行,之后需要切换到系统内核中去获取mutex,在切换的时候,需要将原来用户态的执行指令与内核执行指令相互切换,此时CPU资源也会发生切出切入。

    2019-09-20
    8
  • Liam
    老师好,请教一个问题: 1 非自发场景中,cpu time slice 用完后切换线程,此时被暂停线程是什么状态呢?runnable or blocked, 如果是runnable的话,是不是意味着从runnning到runnable也会导致上下文切换

    作者回复: 我们可以调用yield,线程可以从runnning到runnable,我们可以手动编程试试,看看cs是不是增加了。 yield也会导致上下文切换的。

    2019-06-22
    6
  • 吴青
    老师,你是不是把waiting和timed_waiting状态漏了

    作者回复: 这里指的是系统中线程的五个基本状态,waiting以及timed_waiting属于阻塞,这里的阻塞包括争用锁导致的阻塞blocked状态、调用wait(timeout)导致的timed_waiting状态以及调用wait()导致的waiting状态。

    2019-11-24
    5
  • 欧星星
    使用Synchronized在锁获取的时候会发生CPU上下文切换,多线程本身也会有上下文切换,这样就会多一次切换,是这样吗?

    作者回复: Synchronized在轻量级锁之前,锁资源竞争产生的是线程上下文切换,一旦升级到重量级锁,就会产生进程上下文切换。

    2019-06-22
    5
收起评论
显示
设置
留言
48
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部