由于现在大多数计算机都是多核CPU,多线程往往比单线程更快,可以提高并发性,但是提高并发性并不意味着启动更多的线程来执行。更多的线程意味着线程创建和销毁的成本增加,上下文非常频繁,你的程序无法支持更高的TPS。时间片多任务系统经常需要同时执行多个作业。作业的数量往往大于机器中的CPU数量,但一个CPU同时只能执行一个任务。如何让用户觉得这些任务是同时进行的?操作系统的设计者巧妙地使用了时间片轮转的方法。分配给每个任务(线程)的时间!思考:为什么单核CPU也支持多线程?线程上下文是指某个时间点CPU寄存器和程序计数器的内容。CPU通过时间片分配算法循环执行任务(线程)。因为时间片很短,CPU通过不断切换线程来执行。也就是说,单CPU那么频繁,多核CPU一定程度上可以减少上下文切换。超线程现代CPU除了处理器核心外,还包括寄存器、存储设备如L1L2缓存、浮点运算单元、整数运算单元等辅助运算设备,以及内部总线。多核CPU是指一个CPU上有多个处理器核,这意味着程序的不同线程需要在CPU之间的外部总线上频繁通信,同时还要处理由CPU引起的数据不一致的问题不同CPU之间的不同缓存。超线程的概念是由英特尔提出的。简单的说就是一个CPU上真正并发的两个线程。由于CPU是分时的(如果两个线程A和B,A在使用处理器核心,B在使用Cache或者其他设备,那么AB的两个线程可以并发执行,但是如果AB访问的是同一个设备,则只能在前一个线程执行完毕后执行)。实现这种并发的原理是在CPU上加一个协调辅助核。根据Intel提供的数据,这样的设备会增加5%的设备面积,但性能会提升15%到30%。上下文切换线程切换,同一进程中两个线程的切换进程切换,模式切换两个进程之间的切换,给定线程地址空间中用户态和内核态的切换切换,切换虚拟内存切换前保存当前任务的状态到物理内存CPU,这样下次切换回这个任务的时候可以重新加载这个任务的状态,然后加载执行下一个任务的状态。任务的状态被保存并重新加载。这个过程称为上下文切换。每个线程都有一个程序计数器(记录下一条要执行的指令),一组寄存器(保存当前线程的工作变量),一个栈(记录执行历史,其中每一帧保存一个已被调用但未返回的过程).寄存器是CPU内部的少量快速内存(相对于CPU外部相对较慢的RAM主内存)。寄存器通过提供对常用值(通常是操作中的中间值)的快速访问来提高计算机程序的运行速度。程序计数器是一个专用寄存器,用于指示CPU正在执行的指令序列中的位置,存储的值是正在执行的指令的位置或下一条要执行的指令的位置。挂起当前任务(线程/进程),将这个任务的状态存储在内存中某处的CPU(上下文)中恢复一个任务(线程/进程),在内存中检索下一个任务的上下文,并将其放入CPU的registers,resume跳转到程序计数器指向的位置(即跳转到任务被中断时的代码行)来恢复进程。程序中线程上下文切换有什么问题?上下文切换会造成额外的开销,在高并发执行时往往表现为序列化速度慢,因此减少上下文切换的次数可以提高多线程程序的运行效率。直接消费:指需要保存和加载CPU寄存器,需要执行系统调度器的代码,需要重新加载TLB实例,需要清空CPU流水线。间接消耗:指多核缓存之间共享数据,间接消耗对程序的影响取决于线程工作区中操作数据的大小。Switching在Linux系统下使用vmstat命令查看上下文切换次数,其中cs栏是指上下文切换次数(一般情况下,一个空闲系统每秒的上下文切换次数大概在1500以下)线程调度抢占式调度是指每个线程的执行时间和线程切换都由系统控制。系统控制是指在系统的某种运行机制下,每个线程可能被分配相同的执行时间。时间片,也可能是部分线程执行时间片较长,甚至部分线程没有拿到时间片执行。在这种机制下,一个线程的阻塞不会导致整个进程阻塞。java使用的线程调用采用抢占式调度。Java中的线程会根据优先级分配CPU时间片运行,优先级越高,执行的优先级越高。但是,优先级高并不代表它们可以独占执行时间片。优先级高的获得更多的执行时间片,相反,优先级低的获得的执行时间少,但不会分配不到执行时间。协同调度是指一个线程执行完后,主动通知系统切换到另一个线程执行。这种模式就像一场接力赛。当一个人完成自己的距离后,他将接力棒交给下一个人,下一个人继续前进。撞倒。线程的执行时间由线程自己控制,线程的切换是可以预知的。多线程同步没有问题,但是有一个致命的弱点:如果一个线程写出了问题,就会在运行到一半的时候被阻塞,可能会导致整个系统崩溃。当线程让出CPU时,当前运行的线程主动让出CPU,JVM暂时让出CPU运行(基于时间片轮转调度的JVM操作系统不会让线程永久让出CPU,或者放弃该时间片的执行权),比如调用yield()方法。当前运行的线程由于某些原因进入阻塞状态,例如在I/O上被阻塞。当前运行的线程结束,即run()方法中运行任务后导致线程上下文切换的因素是当前正在执行的任务(线程)的时间片耗尽。之后,系统CPU正常调度下一个任务中断处理。在中断处理过程中,其他程序“中断”了当前正在运行的程序。当CPU接收到中断请求时,它会在正在运行的程序和发起中断请求的程序之间进行上下文切换。中断分为硬件中断和软件中断。软件中断包括由于IO阻塞、抢资源失败或用户代码导致的线程被挂起。用户模式切换,对于一些操作系统,在进行用户模式切换的时候也会进行上下文切换,虽然这不是必须的。多个任务抢占锁资源。在多任务处理中,CPU会在不同的程序之间来回切换。每个程序都有对应的处理时间片。CPU在两个时间片之间进行上下文切换,所以优化方法有:无锁并发编程,在多线程处理数据的时候,可以通过一些方法避免使用锁,比如根据Hash对数据的ID进行分段取模,不同线程处理不同段数据CAS算法,Java的Atomic包使用CAS算法无锁更新数据使用最少线程协程,实现单线程多任务调度,保持单线程多任务切换合理设置线程数不仅可以最大限度地利用CPU,还可以减少线程切换的开销。在高并发和低耗时的情况下,建议少线程。低并发、高耗时情况:推荐使用多线程。高并发高耗时,需要分析任务类型,增加排队,增加线程数。来源:blog.csdn.net/alex_xfboy/article/details/90722654近期文章推荐:1.1,000+Java面试题及答案(2022最新版)2.劲爆!Java协程来了。..3.SpringBoot2.x教程,太全面了!4.不要用爆破爆满画面,试试装饰者模式,这才是优雅的方式!!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!
