1-线程上下文切换介绍
CPU 时间片是 CPU 分配给每个线程执行的时间段,一般为几十毫秒。时间片决定了一个线程可以连续占用处理器运行的时长。当一个线程的时间片用完了,或者因自身原因被迫暂停运行了,这个时候,另外一个线程(可以是同一个线程或者其它进程的线程)就会被操作系统选中,来占用处理器。这种一个线程被暂停剥夺使用权,另外一个线程被选中开始或者继续运行的过程就叫做上下文切换(Context Switch)。
在当前 CPU 数量远远不止一个的情况下,操作系统将 CPU 轮流分配给线程任务,此时的上下文切换就变得更加频繁了,并且存在跨 CPU 上下文切换,比起单核上下文切换,跨核切换更加昂贵。

一个线程的状态由 RUNNING 转为 BLOCKED ,再由 BLOCKED 转为 RUNNABLE ,然后再被调度器选中执行,这就是一个上下文切换的过程。
上下文切换诱因:
一种是程序本身触发的切换,这种我们称为自发性上下文切换,
另一种是由系统或者虚拟机诱发的非自发性上下文切换。
自发性上下文切换指线程由 Java 程序调用导致切出,在多线程编程中,执行调用以下方法或关键字,常常就会引发自发性上下文切换。
sleep(),wait(),yield(),join(),park(),synchronized,lock
非自发性上下文切换指线程由于调度器的原因被迫切出。常见的有:线程被分配的时间片用完,虚拟机垃圾回收导致或者执行优先级的问题导致。
2-优化措施
在多线程编程中,锁其实不是性能开销的根源,竞争锁才是。
减少锁持有时间:没有线程安全的代码块,不用加锁
降低锁力度:比如锁分离(读写锁),分段锁(Java1.8 之前版本的 ConcurrentHashMap 就使用了锁分段)
非阻塞乐观锁替代竞争锁:Java 的 Atomic 包就使用了 CAS 算法来更新数据,就不需要额外加锁。
wait/notify优化:建议使用Lock锁结合Condition 接口替代Synchronized内部锁中的 wait / notify,实现等待/通知。
合理地设置线程池大小,避免创建过多线程
减少Java虚拟机的垃圾回收
文章介绍了线程上下文切换的概念,包括时间片轮转和状态转换,并指出跨CPU核心的切换更为昂贵。上下文切换分为自发性和非自发性两种,前者由程序调用如sleep()、wait()等引发,后者由调度器或系统因素导致。为了优化,文章提出减少锁持有时间、降低锁力度、使用非阻塞乐观锁、优化wait/notify机制以及合理设置线程池大小等策略。

被折叠的 条评论
为什么被折叠?



