什么是多线程的上下文切换,有什么影响?如何进行优化

https://blog.csdn.net/ADbyCool/article/details/107457983

并发编程笔记:什么是多线程的上下文切换,有什么影响?如何进行优化

1.什么是CPU时间片?

CPU会给每个线程分配执行的时间,也就是CPU时间片

CPU时间片是一个小的时间单位,一般为几十毫秒

当线程用完分给它的时间片后,系统的计时器发出时钟中断,调度程序便停止该线程的运行,把它放入就绪队列的末尾;然后把CPU分给其他就绪的线程,同样也让它运行一个时间片,如此往复

2.什么是线程上下文切换?

对于CPU而言,在一个时刻只能运行一个线程,当一个线程的时间片用完,或者因自身原因被迫暂停运行,此时另一个线程会被操作系统选中来占用处理器

当CPU结束运行一个线程,转去执行另外一个线程,这个过程就叫做线程上下文切换

3.线程的上下文具体是什么?

在发生切换的时候,当前线程的任务可能并没有执行完毕。所以在切换时需要保存线程切换前的运行状态,以便下一次,可以接着切换之前的状态继续执行后续的任务

切出切入的过程中,操作系统需要保存和恢复相应的进度信息,这个进度信息就是上下文

4.看一个线程上下文切换的具体例子?

比如一个线程A正在读取一个文件的内容,正读到文件的一半,线程A的时间片结束,此时需要暂停线程A,CPU转去执行线程B

当再次切换回来执行线程A的时候,我们不希望线程A又从文件的开头来读取

5. 上下文的内容一般都有哪些?

一般来说,线程上下文切换过程中会涉及程序计数器、CPU寄存器:

6.什么是CPU寄存器?

寄存器的存储内容:CPU寄存器负责存储已经、正在和将要执行的任务
在线程正在进行某个计算的时候被挂起了,那么下次继续执行的时候需要知道之前挂起时变量的值时多少

7.什么是程序计数器?

程序计数器存储的指令内容:程序计数器负责存储CPU正在执行的指令位置、即将执行的下一条指令的位置

线程在进行切换时候,需要知道在这之前当前线程已经执行到哪条指令了,这些指令信息需要依靠程序计数器来保存

程序计数器是一块较小的内存空间
它保存了当前线程下一条需要执行的字节码指令的位置

每条线程都需要有一个独立的程序计数器
线程之间的程序计数器互不影响
堆是共享的
而程序计数器一定是线程私有的

8.线程上下文切换为什么会消耗系统资源?

Java的线程底层是映射到操作系统原生线程之上的
如果要阻塞或唤醒一个线程就需要操作系统介入
需要在用户态与内核态之间切换
这种切换会消耗大量的系统资源

9.什么是用户态?

在执行用户自己的代码时,称其处于用户态
此时处理器特权级别最低
是普通的用户进程运行的特权级
大部分用户直接面对的程序都是运行在用户态

10.什么是内核态?

当因为系统调用陷入内核代码中执行时处于内核态
此时处理器处于特权级最高

11.用户态和内核态切换需要传递和保存哪些东西?

如果要执行文件操作、网络数据发送等操作必须通过write、send等系统调用
此时需要从用户态切换到内核态。
这些系统调用会调用内核的代码
在执行完后又会切换回用户态

用户态与内核态都有各自专用内存空间和专用寄存器等

用户态切换至内核态需要传递给许多变量、参数给内核

内核也需要保护好用户态在切换时的一些寄存器值、变量等,以便内核态调用结束后切换回用户态继续工作

12.线程上下文切换一般分为哪两种?

第一种:自发性上下文切换

第二种:非自发性上下文切换

13.自发性上下文切换一般使用哪些方法?

sleep()
wait()
yield()
join()

park()即真正让线程停止下来(阻塞),Java提供了一个较为底层的并发工具类:LockSupport,该类常用的方法有两个
1.park(Object blocker) 表示阻塞指定线程,参数blocker当前线程对象
2 unpark(Thread thread) 唤醒指定线程,参数thread指定线程对象

synchronized
lock

14.哪些是非自发性上下文切换?

线程被分配的时间片用完
JVM垃圾回收(STW、线程暂停)
线程执行优先级

15.线程上下文切换带来的系统开销如何优化?

线程上下文切换带来的系统消耗不可避免
核心思想:减少线程上下文切换的出现

优化一:减少锁的竞争

优化二:减少锁的持有时间

优化三:减少锁的粒度中的锁读写分离

优化四:减少锁的粒度中的锁分段

优化五:用非阻塞乐观锁代替竞争锁

优化六:减少GC频率

16.减少上下文切换为什么要减少锁的竞争?

多线程对锁资源的竞争,如果失败由于进入阻塞状态,将会引起上下文切换

锁竞争导致的线程阻塞越多
锁竞争带来很多次的上下文切换
系统的性能开销就越大

在多线程编程中,锁本身不是性能开销的根源
锁竞争才是性能开销的根源

锁优化归根到底是减少竞争

17.减少上下文切换为什么要减少锁的持有时间?

锁的持有时间越长,意味着越多的线程会被阻塞,在等待该竞争锁释放

优化方法:将一些与锁无关的代码移出同步代码块,尤其是那些开销较大的操作以及可能被阻塞的操作

18.减少上下文切换为什么要减少锁粒度中的锁读写分离?

读写锁实现了锁分离
由读锁和写锁两个锁实现,
可以共享读,但只有一个写

读写锁在多线程读写时,
读读不互斥
读写互斥,写写互斥

传统的独占锁在多线程读写时
读读互斥,读写互斥,写写互斥

在读远大于写的多线程场景中,锁分离避免了高并发读情况下的资源竞争,从而避免了上下文切换

19.减少上下文切换为什么要减少锁的粒度中的锁分段?

在使用锁来保证集合或者大对象的原子性时
可以将锁对象进一步分解

Java 1.8之前的ConcurrentHashMap就是用了锁分段

20.减少上下文切换为什么可以用非阻塞乐观锁代替竞争锁?

CAS是一个原子的if-then-act操作

CAS是一个无锁算法实现
保障了对一个共享变量读写操作的一致性

CAS不会导致上下文切换,Java的Atomic包就使用了CAS算法来更新数据,而不需要额外加锁

21.减少上下文切换为什么要减少GC频率?

很多垃圾回收器在回收旧对象时会产生内存碎片
从而需要进行内存整理
该过程需要移动存活的对象

而移动存活的对象意味着这些对象的内存地址会发生改变
因此在移动对象之前需要暂停线程
完成后再唤醒线程
因此减少GC的频率能够有效的减少上下文切换

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值