Java 并发高频面试题及详细答案(实战向、无机器话术)_第1页
Java 并发高频面试题及详细答案(实战向、无机器话术)_第2页
Java 并发高频面试题及详细答案(实战向、无机器话术)_第3页
Java 并发高频面试题及详细答案(实战向、无机器话术)_第4页
Java 并发高频面试题及详细答案(实战向、无机器话术)_第5页
已阅读5页,还剩2页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java并发高频面试题及详细答案(实战向、无机器话术)一、线程基础核心面试题1.说说线程和进程的区别?参考答案:进程是操作系统资源分配的最小单位,线程是CPU调度执行的最小单位。简单来说,一个程序运行起来就是一个进程,一个进程里可以包含多个线程。核心区别有四点:1.资源占用:进程独立占有内存、CPU等系统资源,开销极大;线程共享所在进程的资源,创建和销毁开销很小。2.独立性:进程之间完全隔离,一个进程崩溃不会影响其他进程;线程之间共享资源,一个线程出问题,大概率会导致整个进程挂掉。3.通信方式:进程通信复杂,需要管道、socket、共享内存等特殊方式;线程通信简单,直接读写进程内的共享变量即可。4.切换成本:进程切换需要刷新页表、缓存,成本很高;线程只需要切换栈和寄存器,成本极低。2.Java中线程的生命周期有哪几种状态?分别是什么场景?参考答案:Java线程一共6种状态,源码Thread.State枚举中定义,日常开发高频用到五种:1.NEW(新建):new了线程对象,但还没调用start()方法,线程未启动。2.RUNNABLE(可运行):调用start()后进入该状态,包含两种情况:正在CPU运行、等待CPU分配时间片。3.BLOCKED(阻塞):线程等待获取synchronized锁,没抢到锁就挂起,不占用CPU。6.TERMINATED(终止):线程代码执行完毕,或者异常退出,线程彻底结束。3.start()和run()的区别?为什么不能直接调用run()?参考答案:1.start():是启动线程的核心方法,会向操作系统申请创建新线程,由JVM调度执行run()方法,真正实现多线程并发执行,只能调用一次,多次调用会抛异常。2.run():只是一个普通成员方法,直接调用就是当前主线程同步执行代码,没有开启新线程,不存在并发效果,可以重复调用。简单总结:调用start()才是多线程,直接调run()就是普通顺序执行。二、锁与线程安全核心面试题1.说说synchronized的原理和使用场景?是公平锁还是非公平锁?可重入吗?参考答案:synchronized是Java原生的悲观锁,用来保证多线程下代码的原子性、可见性、有序性,解决线程安全问题。使用场景分三种:1.修饰普通方法:锁的是当前对象this;2.修饰静态方法:锁的是当前类的Class对象;3.修饰代码块:锁的是括号内指定的对象。核心特性:1.可重入:同一个线程可以多次获取同一把锁,不会自己卡死自己,底层依靠锁计数器实现;2.非公平锁:线程抢锁随机,不会按照等待顺序执行,效率更高,但可能出现线程饥饿;3.自动释放锁:代码执行完毕或抛出异常,JVM会自动释放锁,不会死锁。底层原理:依靠对象头的MarkWord实现,存在锁升级机制:无锁→偏向锁→轻量级锁→重量级锁,逐步升级,不会降级,适配不同并发场景。2.ReentrantLock和synchronized的区别?实际开发怎么选型?参考答案:两者都是可重入锁,核心区别集中在灵活性和功能上:1.锁实现层面:synchronized是JVM底层原生实现,自动加锁解锁;ReentrantLock是代码层面实现的锁,需要手动lock()、unlock()。2.公平锁支持:synchronized只能是非公平锁;ReentrantLock可以指定公平/非公平锁。3.中断等待:synchronized等待锁时无法被中断;ReentrantLock支持可中断抢锁,避免线程一直阻塞。4.超时抢锁:ReentrantLock可以设置抢锁超时时间,抢不到直接放弃,有效避免死锁;synchronized不支持。5.条件唤醒:ReentrantLock可以绑定多个Condition,精准唤醒指定线程;synchronized只能随机唤醒一个或全部线程。开发选型原则:简单同步场景、代码量少,优先用synchronized,简洁省心,不易出错;需要公平锁、超时抢锁、精准唤醒、可中断场景,必须用ReentrantLock。3.什么是死锁?产生死锁的四个必要条件?如何避免死锁?参考答案:死锁就是多个线程互相持有对方需要的锁,同时又互相等待对方释放锁,导致所有线程永久阻塞,程序卡死。四个必要条件(缺一不可):1.互斥条件:锁同一时间只能被一个线程持有;2.请求与保持:线程持有一把锁,同时去请求另一把被占用的锁,不释放已有锁;3.不可剥夺:别人持有的锁,不能被强行抢占,只能等待主动释放;4.循环等待:线程之间形成锁等待闭环,A等B的锁,B等C的锁,C等A的锁。避免方案:破坏任意一个条件即可,最常用的是统一锁的获取顺序,所有线程都按固定顺序抢锁;其次是设置抢锁超时时间、减少锁嵌套、尽量缩短锁持有时间。三、线程池高频面试题1.为什么要用线程池?手动newThread有什么问题?参考答案:手动创建线程弊端非常多,生产环境绝对禁止频繁newThread:1.资源开销大:线程创建、销毁需要系统资源,频繁创建销毁会浪费CPU和内存,造成资源抖动;2.不可控:无限创建线程会导致线程数量过多,上下文切换频繁,系统负载飙升,最终OOM宕机;3.无法复用:线程执行完任务就销毁,不能重复利用,性能极低;4.无统一管理:线程分散,无法监控、统计任务执行情况,异常难以统一处理。线程池核心优势:线程复用、控制并发数量、降低资源开销、统一管理任务、支持超时、拒绝策略等,适配业务并发场景。2.线程池核心参数有哪些?各自含义?参考答案:核心线程池ThreadPoolExecutor七大参数,面试重点记核心5个:1.corePoolSize核心线程数:线程池常驻线程数,即使空闲也不会被回收,一直等待处理任务;2.maximumPoolSize最大线程数:线程池能容纳的最大线程总数,核心线程不够用、队列满了才会创建非核心线程;3.keepAliveTime空闲超时时间:非核心线程空闲超过该时间,会被自动回收;4.workQueue任务队列:存储等待执行的任务,核心线程忙完后,新任务进入队列排队;5.handler拒绝策略:线程数达到最大值、队列也满了,触发拒绝策略处理新任务。额外两个:线程工厂(创建线程,可自定义线程名、守护线程)、超时时间单位。3.线程池任务执行流程?参考答案:1.提交任务后,首先判断核心线程数,当前运行线程数小于核心数,直接新建核心线程执行任务;2.核心线程已满,判断任务队列,队列没满,任务存入队列排队;3.队列已满,判断最大线程数,当前线程数小于最大值,新建非核心线程执行任务;4.线程数已经达到最大值、队列也满了,触发拒绝策略处理新任务。4.线程池四种拒绝策略?实际开发怎么选?参考答案:1.AbortPolicy(默认):直接抛出异常,中断任务提交,适合核心业务,任务丢失不可接受的场景;2.CallerRunsPolicy:谁提交任务谁执行,也就是主线程自己跑,不会丢任务,能削峰限流,适合非核心、允许延迟的业务;3.DiscardPolicy:直接丢弃新任务,不抛异常、无日志,适合无关紧要的日志、监控类任务;4.DiscardOldestPolicy:丢弃队列最旧的未执行任务,替换为新任务,适合时效性强、新任务优先的场景。生产建议:不建议用默认策略,核心业务用自定义拒绝策略(打印日志、告警、重试),非核心业务用CallerRunsPolicy。5.阿里开发规范为什么禁止用Executors创建线程池?参考答案:Executors创建的线程池参数不透明,底层存在严重风险,容易引发线上OOM:1.newFixedThreadPool:队列是无界队列,任务无限堆积,内存溢出;2.newCachedThreadPool:最大线程数无限,高并发下会创建海量线程,直接打垮服务;3.newSingleThreadExecutor:同样无界队列,任务堆积OOM风险极高。所以生产环境必须手动通过ThreadPoolExecutor构造方法创建线程池,自定义核心参数、队列大小、拒绝策略,风险可控。四、volatile与并发内存模型1.volatile关键字的作用?能保证线程安全吗?参考答案:volatile有两个核心作用:保证可见性、禁止指令重排,不保证原子性,所以不能保证整体线程安全。1.可见性:一个线程修改了volatile变量,会立刻刷新到主内存,其他线程能实时感知到最新值,解决变量缓存导致的脏数据问题;2.禁止重排:底层通过内存屏障实现,避免编译器、CPU优化时打乱代码执行顺序,解决单例模式双重锁的空指针问题;3.不保证原子性:复合操作(i++、i+=1)是读-改-写三步操作,volatile只能保证每次读取最新值,无法保证三步操作不被打断,多线程下依然会有数据错乱。使用场景:状态标记量、开关变量、双重校验锁单例。2.什么是JMM内存模型?核心规则是什么?参考答案:JMM是Java定义的内存抽象模型,用来屏蔽不同硬件、操作系统的内存差异,统一多线程内存可见性、重排规则,保证Java程序跨平台并发正确性。核心规则:所有变量存在主内存,每个线程有自己的工作内存,线程操作变量只能在工作内存进行,读写需要和主内存同步。由此引出并发三大特性:可见性、原子性、有序性,synchronized、volatile、Lock都是为了保证这三大特性。五、并发工具类面试题1.CountDownLatch、CyclicBarrier、Semaphore的区别和使用场景?参考答案:三者都是JUC并发工具,用途完全不同:1.CountDownLatch(倒计时计数器)核心:一次性使用,倒计时结束后不能重置。作用是主线程等待多个子线程执行完毕。场景:批量异步处理任务,所有子任务完成后,主线程汇总结果。2.CyclicBarrier(循环栅栏)核心:可循环复用。作用是多个线程互相等待,全部到达临界点后再一起执行。场景:多线程分批执行任务,每批线程全部就绪后统一下一步操作。3.Semaphore(信号量)核心:控制并发线程数量,限流作用。作用是限制同时执行的线程数。场景:接口限流、连接池资源控制(数据库连接、Redis连接)。2.ConcurrentHashMap1.7和1.8的区别?线程安全原理?参考答案:ConcurrentHashMap是并发安全的键值对集合,替代Hashtable,并发性能远优于Hashtable。JDK

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论