java面试题多线程,多线程高并发面试题

  java面试题多线程,多线程高并发面试题

  由于现在大部分电脑都是多核CPU,多线程往往比单线程快,可以提高并发性,但是提高并发性并不意味着启动更多的线程来执行。更多的线程意味着线程创建和销毁的成本增加,上下文非常频繁,但是你的程序无法支持更高的TPS。

  时间片多任务系统经常需要同时执行多个任务。作业的数量通常大于机器中CPU的数量。然而,一个CPU在同一时间只能执行一个任务。如何让用户感觉到这些任务在同时进行?操作系统的设计者巧妙地运用了时间片轮换的方式。

  时间片是CPU分配给每个任务(线程)的时间!

  "

  思考:为什么单核CPU也支持多线程?

  "

  上下文是指在某个时间点CPU寄存器和程序计数器的内容。CPU通过时间片分配算法循环执行任务(线程)。因为时间片很短,CPU通过不断切换线程来执行。

  换句话说,单CPU如此频繁,多核CPU可以在一定程度上减少上下文切换。

  超线程【现代CPU包括寄存器、L1L2缓存、浮点运算器、整数运算器等辅助运算器,以及内部总线等。除了处理器核心之外。多核CPU,即一个CPU有多个处理器核,这意味着程序的不同线程需要在CPU之间的外部总线上频繁通信,同时还要处理不同CPU之间缓存不同导致的数据不一致。]

  【超线程的概念是英特尔提出的。简单来说,就是同一个CPU上真正的并发两个线程。由于CPU都是分时的(如果两个线程A和B,A在使用处理器内核,B在使用缓存或其他设备,那么两个线程AB可以并发执行,但是如果AB都在访问同一个设备,那么一个线程只能等到前一个线程执行完)。实现这种并发的原理是给CPU增加一个协调辅助核。根据Intel提供的数据,这样的器件会增加5%的器件面积,但性能会提升15%~30%。]

  【上下文切换】【线程切换,在同一个进程的两个线程之间切换】【进程切换,在两个进程之间切换】【模式切换,在给定的线程中在用户模式和内核模式之间切换】【地址空间切换,将虚拟内存切换到物理内存】【保存当前任务之前的状态】【CPU切换,这样下次再切换回这个任务的时候,可以重新加载这个任务的状态,然后加载执行下一个任务的状态。保存和重新加载任务状态的过程称为上下文切换。]

  【每个线程都有一个程序计数器(记录下一条要执行的指令),一组寄存器(保存当前线程的工作变量),一个堆栈(记录执行历史,其中每帧保存一个已经调用但没有返回的过程)。]

  【寄存器是CPU内部的一个小而快的内存(对应CPU外部相对较慢的RAM主存)。寄存器可以快速访问常用值(通常是运算的中间值),提高计算机程序的运行速度。]

  【程序计数器是一个特殊的寄存器,用来指示CPU在指令序列中的执行位置。存储的值是正在执行的指令的位置或下一条要执行的指令的位置。]

  [暂停当前任务(线程/进程)并将该任务的状态(上下文)存储在CPU内存中的某个地方][恢复一个任务(线程/进程),在内存中检索下一个任务的上下文并将其恢复到CPU的寄存器中][跳转到程序计数器指向的位置(即任务中断时跳转到代码行)以在程序中恢复该进程]

  线程上下文切换有什么问题?上下文切换会导致额外的开销,往往表现为并发执行高,串行执行慢。因此,减少上下文切换的次数可以提高多线程程序的运行效率。

  直接消耗:需要保存和加载CPU寄存器,需要执行系统调度器代码,需要重新加载TLB实例,需要刷掉CPU流水线。间接消耗是指多核缓存之间的共享数据。间接消耗对程序的影响取决于线程工作区中操作数据的大小。使用vmstat命令检查Linux系统下的上下文切换次数,其中cs列指的是上下文切换的次数(一般情况下,空闲系统中的上下文切换都在每秒1500以下。

  线程调度抢占式调度是指每个线程的执行时间和线程切换都由系统控制。系统控制是指在系统的某种运行机制下,每个线程可能有相同的执行时间片,或者有些线程可能有更长的执行时间片,甚至有些线程可能不执行。在这种机制下,一个线程的阻塞不会导致整个进程的阻塞。

  java中使用的线程使用抢占式调度。在Java中,线程会根据优先级分配CPU时间片来运行,优先级越高,优先级越高。但是,更高的优先级并不意味着它们可以单独占用执行时间片。可能优先级越高,执行时间片就越多。相反,优先级越低,分配的执行时间就越少。

  协同调度是指在一个线程执行完毕后,主动通知系统切换到另一个线程。这种模式就像接力赛,一个人完成自己的旅程后把接力棒交给下一个人,下一个人继续往下跑。线程的执行时间由线程自身控制,线程切换是可以预测的。不存在多线程同步的问题,但是它有一个致命的弱点:如果一个线程写的有问题,那么在运行当中就会被阻塞,可能会导致整个系统崩溃。

  线程放弃了cpu。当前运行的线程主动放弃CPU,JVM暂时放弃CPU操作(基于时间片轮换调度的JVM操作系统不会让线程永久放弃CPU,或者放弃这个时间片的执行权),比如调用yield()方法。当前正在运行的线程因为某些原因进入阻塞状态,比如阻塞I/O,当前正在运行的线程结束,也就是run()方法中的任务结束后,线程上下文切换。当前正在执行的任务(线程)的时间片用完后,系统CPU正常调度下一个任务来中断,其他程序在中断处理过程中“中断”当前正在运行的程序。当CPU收到一个中断请求时,它将在正在运行的程序和发起中断请求的程序之间进行上下文切换。中断分为硬件中断和软件中断。软件中断包括由于IO阻塞、无法获取资源或用户代码而导致的线程暂停。用户模式切换。对于某些操作系统,当执行用户模式切换时,还会执行上下文切换,尽管这不是必需的。多个任务抢占锁资源。在多任务处理中,CPU在不同程序之间来回切换,每个程序都有对应的处理时间片。因此,CPU在两个时间片之间的间隔中切换上下文。所以优化方法有:无锁并发编程。多线程处理数据时,可以用一些方法避免使用锁,比如将数据id按照Hash划分成模块,用CAS算法用不同的线程处理不同的段。Java原子包使用CAS算法更新数据,不加锁,使用最少的线程协调。多任务调度在单线程中实现,多任务之间的切换在单线程中维护。合理设置线程数量,不仅可以最大化CPU利用率,还可以降低线程切换的成本。

  在高并发、低耗时的情况下,建议少用线程。低并发高耗时:推荐多线程。高并发且耗时,所以需要分析任务类型,增加队列,增加线程数量。版权归作者所有:原创作品来自博主小二上九8,转载请联系作者取得转载授权,否则将追究法律责任。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: