java - 面试题-多线程并发编程
基础知识为什么要是使用并发编程提升多核CPU的利用率,一般来说一台主机上的会有多个CPU核心,我们可以创建多个线程,理论上讲操作系统可以将多个线程分配给不同的CPU去执行,每个CPU执行线程,这样就提高了CPU的使用效率,如果使用单线程就只能有一个CPU核心被使用。比如当我们在网上购物时,为了提升响应速度,需要拆分,减库存,生成订单等等这些操作。就可以进行拆分进行多线程的技术完成,面对复杂业务模型,并行程序会比串行程序更适应业务需求,而并发编程更能吻合这种业务拆分。
并发编程三个必要因素是什么?原子性:即一个不可再被分割的颗粒,操作要从头到尾一口气执行完毕,不能被其他操作所中断。可见性:一个线程对共享变量的修改,另一个线程能够立刻看到。有序性:程序执行的顺序按照代码的先后顺序执行。(处理器可能会对指令进行重排序)Java程序中怎么保证多线程的运行安全的呢?
做一个形象的比喻:
并发 = 俩个人用一台电脑。
并行 = 俩个人分配了俩台电脑。
串行 = 俩个人排队使用一台电脑。多线程的好处
简单来说就是:
充分利用多核CPU的计算能力。方便进行业务拆分,提升应用性能。多线程应用场景例如:迅雷多线程下载、数据库连接池、分批发送短信等等。
并发编程有什么缺点并发编程的目的就是为了能提供程序的执行效率,提供程序运行速度,但是并发编程并不总是能提高程序运行速度的,而且并发编程可能会遇到很多问题,比如:内存泄漏、上下文切换、线程安全、死锁等等问题。
并发编程三个必要因素是什么?原子性:即一个不可再被分割的颗粒,操作要从头到尾一口气执行完毕,不能被其他操作所中断。可见性:一个线程对共享变量的修改,另一个线程能够立刻看到。有序性:程序执行的顺序按照代码的先后顺序执行。(处理器可能会对指令进行重排序)Java程序中怎么保证多线程的运行安全的呢?
出现线程安全问题的原因一般都是三个原因:
线程切换带来的原子性问题;解决办法:使用多线程之间同步synchronized或者使用锁lock。缓存导致的可见性问题;解决办法:synchronized、volatile、lock,可以解决可见性问题编译优化带来的有序性问题;解决办法:happens-Before 规则可以解决有序性问题并行并发、串行有什么区别?并发:多个任务在同一个CPU核上,按细分的时间片轮流交替执行,从宏观上看这些任务好像是同时进行似的(其实不是)并行:单位时间内,多个处理器或多核处理器同时处理多个任务,是真正意义上的“同时进行”。串行:有n个任务,由一个线程按顺序执行。由于任务、方法都在一个线程执行所以不存在线程不安全情况,也就不存在临界区的问题。做一个形象的比喻:
并发 = 俩个人用一台电脑。
并行 = 俩个人分配了俩台电脑。
串行 = 俩个人排队使用一台电脑。多线程的好处
可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其他的线程而不是等待,这样就大大提高了程序的效率。也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
多线程的劣势线程也是程序,所以线程需要占用内存,线程越多占用内存也越多。多线程需协调和管理,所以需要CPU时间跟踪线程线程之间对共享资源的访问会相互影响,必须解决竞争使用共享资源的问题。线程和进程的区别线程属于进程,线程是进程的一部分。线程不能脱离进程而存在一个进程中的多个线程可以共享一部分相同的资源,同时还拥有部分自己独有的资源例如程序计数器。而进程与进程之间一般是相互独立的,不存在内存资源共享的情况。一个进程中一个线程的崩溃可能会影响其他线程的运行,而一个系统中一个进程的崩溃,大部分情况并不会影响其他进程的长正常运行。什么是上下文切换?在我们平时的的多线程编程中,大部分情况下,我们的创建的线程数是大于我们主机电脑CPU的核心数的。而CPU的一个核心同一个时刻只能执行一个线程,为了能够让其他多余的线程也能被CPU所关照到。我们就需要让CPU轮流去指向这些多余的线程,给每个线程分配一个时间片。当一个线程的时间片被消耗完毕后,CPU就会让这个线程进入休眠状态,让已经进行准备运行状态的线程获得CPU的使用权。这个从一个线程切换到另外一个线程的过程,就叫做上下文切换。
守护线程和用户线程有什么区别呢?用户进程:就是我们平时windows电脑上前台所运行的QQ、微信程序,或者是Linux服务器上运行的Java jar服务。守护进程:而守护进程呢,则是依附其对应的用户进程而存在的。为其用户进程而服务,随着用户进程的消亡,而毁灭。如何在Linux 上查找哪个线程cpu利用率最高?终端执行top命令,然后shift + p找出cpu利用率最高的进程pid号(如果是排查内存占用问题,则shift+m)根据上面拿到的pid好,执行top -H -p pid号,然后继续按下shift + p,找到cpu占有率最高的线程然后将获取到的线程pid号转换为16进制,使用jstack工具,jstack pid号 > /tmp/t.dat,如jstack 21324 > /tmp/t.dat然后vim刚才的文件,找到线程号对应的信息什么是线程死锁死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程(线程)称为死锁进程(线程)。多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。版权声明
本文仅代表作者观点,不代表博信信息网立场。