上下文切换

单核处理器也支持多线程代码,CPU通过给每个线程分配CPU时间片来实现.

CPU通过时间片分配算法来循环执行业务,任务执行一个时间片后会切换到下一个任务.任务从保存到加载的过程就是一次上下文切换.

上下文切换会影响多线程的执行速度.

并发操作不一定快,创建线程及上下文切换有固有的开销.

测试切换次数及时长

使用 LMbench3 测量上下文切换时长

使用vmstat测量上下文切换次数

1
2
3
4
5
6
vmstat 1

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
6 0 0 24836616 1829476 41996652 0 0 48 153 0 0 17 8 75 0 0
19 0 0 24830244 1829476 41997324 0 0 0 0 250198 624179 12 8 80 0 0

CS(Content Switch)表示上下文切换的次数

如何减少上下文切换次数

  • 无锁并发编程.多线程竞争锁时,会引起上下文切换,所以处理数据时,可以通过避免使用锁减少上下文切换(例:数据Hash取模分段,不同线程处理不同的数据).
  • CAS算法.(例:Atomic包使用了CAS算法来更新数据,不需要加锁)
  • 使用最少线程.避免创建不需要的线程,线程数创建过多会导致大量线程处于等待状态.
  • 协程:在单线程里实现多任务调度,并在单线程里维持多个任务间的切换

实际操作

用jstack命令dump线程信息

1
jstack 203 > /home/w/www/dump

统计线程状态分布

1
2
3
4
5
6
7
8
grep "java.lang.Thread.State" dump1 | sort | uniq -c

201 java.lang.Thread.State: RUNNABLE
2 java.lang.Thread.State: TIMED_WAITING (on object monitor)
79 java.lang.Thread.State: TIMED_WAITING (parking)
20 java.lang.Thread.State: TIMED_WAITING (sleeping)
3 java.lang.Thread.State: WAITING (on object monitor)
592 java.lang.Thread.State: WAITING (parking)

查看 WAITING (on object monitor)状态的线程的具体情况,例如线程闲置,需要调小线程池容量

文章链接 https://fangzongzhou.github.io/2020/09/25/计算机/技术栈/Java/并发编程/上下文切换/