[db:标题]

摘要:多线程中的上下文切换是什么?你觉得什么是线程安全?并行和并发有什么区别?守护线程与普通线程有什么区别?JDK21中的虚拟线程是什么?
多线程中的上下文切换是什么? 上下文切换 是指CPU从一个线程切换到另一个线程时,需要保存当前线程的上下文状态,然后恢复另一个线程的上下文状态,这样下次恢复执行该线程时也能够正确的执行。 多线程中的上下文切换 在多线程的情况下,线程上下文的切换是一种常见的操作,通常是在一个CPU上,由于多个线程共享CPU的时间片,一个线程的时间片用完后,切换到另一个线程运行时,要保存当前线程的状态信息,包括程序计数器,寄存器,栈指针等。以便下次执行该线程时,能恢复到正确的状态。 由于是在多线程的情况下,所以上下文切换的开销比单线程的开销大,因为多线程下需要保存和恢复更多的上下文信息。过多的上下文切换会降低系统的运行效率,因此需尽可能少的避免线程上下文切换次数。 避免频繁切换上下文的方法: 降低线程数,通过合理的线程池来管理线程,减少线程的创建和销毁,并不是线程数越多越好,合理的线程数可以避免线程过多的上下文切换。 采用无锁并发编程,可以避免线程因等待锁而进入阻塞状态,从而减少上下文切换的发生。 用CAS算法,CAS这种乐观锁的算法,可以避免线程的阻塞和唤醒操作,从而减少上下文切换。 合理是使用锁,在使用锁的过程中,避免过多地使用同步块或同步方法,一定要用的化,要尽量缩小同步块儿和同步方法的范围,从而减少线程的阻塞时间,减少上下文的切换。 使用协程(JDK19的虚拟线程),这是一种用户态的线程,其切换不需要操作系统的参与,因此可以避免上下文的切换(JVM层面还是会有一些保存和恢复线程的状态)。 你觉得什么是线程安全? 线程安全是指在多线程并发的情况下,能够正确的处理多线程之间的共享变量,使程序能够正确的执行。 这里所说的程序能够正确执行,主要是满足所谓的原子性、有序性和可见性。 共享变量 共享变量,即所有线程都可以操作的变量。 在操作系统中,进程是分配资源的基本单位,线程是执行的基本单位,因此多个线程是可以共享进程中的数据。在JVM中,堆和方法区的区域是多个线程共享的数据区域。 那么哪些变量是保存在堆和方法区中的呢,哪些变量又是保存在栈中的呢? 堆 方法区(元空间) 栈 类变量 实例变量 局部变量 public class VarTest { /** * 类变量 */ public static String ClassVar = "ClassVar"; /** * 实例变量 */ public String entityVar = "entityVar"; /** * 局部变量 */ public void logMethodVar(){ // 局部变量 int methodIntVar = 1; System.out.println(methodIntVar); } } 并行和并发有什么区别 并发(concurrency),在操作系统中,同一时间有多个程序处于运行中,且这几个程序是在同一个CPU中执行。 对于单个CPU来说,同一时间只能干一件事情,为了看起来像是同事干多件事情,操作系统把CPU的时间划分成长短基本相同的时间区间,也就是“时间片”,通过操作系统的管理,把这些时间片依次轮流地分配给各个用户使用。 并行(parallel),当操作系统有一个以上的CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互相不抢占CPU资源,可以同时进行。 两者的关键性区别 并行是物理上的同时执行,而并发是逻辑上的同时执行。 并行通常需要更多硬件资源(如多核CPU),并发则更注重任务调度的效率。 并行的目标是加速单个任务(通过拆分任务并行处理),而并发的目标是处理更多任务(通过快速切换)。 守护线程与普通线程有什么区别 守护线程(Daemon Thread)和普通用户线程(User Thread),是两种不同类型的线程,两者都是可以通过Thread类或Runnable接口创建的。 两者最大的区别在于:JVM会等待所有普通用户线程执行完毕后才退出。JVM不会等待守护线程完成,当所有普通线程结束时,JVM会强制终止所有守护线程。 守护线程一般被用来执行后台任务,最典型的场景就是JVM的GC(垃圾回收器)。 还有一些场景例如: 日志记录(异步写入日志) 定时任务监控(如心跳检测) 资源清理(缓存清理) JDK19出现的虚拟线程,也是守护线程。
阅读全文