强某学习记录

75 阅读3分钟

2.4

多线程中的上下文切换

上下文切换是指 CPU 从一个线程转到另一个线程时,需要保存当前线程的上下文状态,恢复另一个线程的上下文状态,以便于下一次恢复执行该线程时能够正确地运行。 上下文切换通常是指在一个 CPU 上,由于多个线程共享 CPU时间片,当一个线程的时间片用完后,需要切换到另一个线程运行。

初步个人理解:3000个账户获取余额,CPU8核16线程,所以得开3000个线程,3000/16=187。这里是不是得切187次线程,是不是这里开销

二次理解 3000个是线程池队列长度,但是核心线程一般也是16或32,所以这里体现的不会很明显。32的时候可能会出现,出现在16个空闲16个运行,然后存在切换

解决办法:

  1. 减少线程数:可以通过合理的线程池管理来减少线程的创建和销毁,线程数不是越多越好合理的线程数可以避免线程过多导致上下文切换。
  2. 使用无锁并发编程:无锁并发编程可以避免线程因等待锁而进入阻塞状态,从而减少上下文切换的发生
  3. 使用CAS算法:CAS算法可以避免线程的阻塞和唤醒操作,从而减少上下文切换
  4. 使用协程(JDK 19的虚拟线程):协程是一种用户态线程,其切换不需要操作系统的参与,因此可以避免上下文切换。(避免的是操作系统级别的上下文切换,但是仍然需要在M层面做一些保存和恢复线程的状态,但是也成本低得多)
  5. 合理地使用锁:在使用锁的过程中,需要避免过多地使用同步块或同步方法,尽量缩小同步块或同步方法的范围,从而减少线程的等待时间,避免上下文切换的发生

线程状态

分为6种:

  1. 初始(NEW):新创建了一个线程对象,但还没有调用start0)方法。
  2. 运行(RUNNABLE):Java线程中将就绪(READY)和运行中(RUNNING)两种状态笼统的称为“运行”

就绪(READY):线程对象创建后,其他线程(比如main线程)调用了该对象的start0)方法。该状态的线程位于可运行线程池中,等待被线程调度选中并分配cpu使用权。
运行中(RUNNING):就绪(READY)的线程获得了cpu时间片,开始执行程序代码 3. 阻塞(BLOCKED):表示线程阻塞于锁(关于锁,在后面章节会介绍)。 4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断) 5. 超时等待(TIMED WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。 6. 终止(TERMINATED):表示该线程已经执行完毕。

注:为什么ready和running是runnable,因为会切换CPU,多线程可能是一个CPU,不同线程运行。因此可能会在ready,可能会在running,不好区分,因此使用一个

WAITING和TIMEED WAITING

WARITING是等待,一般是wait操作的。wait操作在JAVA对象上,在OBJECT类里面,会释放锁。TIMEED WAITING是超时等待,他是线程操作,不会释放锁。