Java Concurrent 高频面试题及详细答案(实战口语版)_第1页
Java Concurrent 高频面试题及详细答案(实战口语版)_第2页
Java Concurrent 高频面试题及详细答案(实战口语版)_第3页
Java Concurrent 高频面试题及详细答案(实战口语版)_第4页
Java Concurrent 高频面试题及详细答案(实战口语版)_第5页
已阅读5页,还剩2页未读, 继续免费阅读

下载本文档

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

文档简介

JavaConcurrent高频面试题及详细答案(实战口语版)一、并发基础核心题1.并行和并发的区别是什么?简单说,并发是交替执行,并行是同时执行。并发:单个CPU核心快速切换多个线程,宏观看着是一起跑,微观上同一时间只有一个线程在执行,比如秒杀系统同时处理大量请求,靠线程切换实现吞吐。并行:多个CPU核心同时执行多个线程,同一时间多个任务真正同时运行,比如大数据多线程分片计算。总结:并发侧重高吞吐、任务交替执行,并行侧重任务同时执行、提升计算速度。2.进程和线程的区别?进程是资源分配的最小单位,线程是CPU调度的最小单位。1)进程相互独立,有独立的内存空间,一个进程崩溃不影响其他进程;线程共享所在进程的堆和方法区资源,一个线程异常崩溃,整个进程大概率挂掉。2)进程创建、销毁、切换开销极大;线程开销很小,轻量化。3)进程之间通信复杂,需要管道、socket等;线程之间直接共享变量,通信简单但有线程安全问题。3.线程的五大状态及流转过程?核心五大状态:新建、就绪、运行、阻塞、终止。1)新建(NEW):newThread之后,未调用start(),只是创建了对象,没有启动线程。2)就绪(RUNNABLE):调用start()后,线程进入就绪队列,等待CPU调度,具备执行资格但没拿到CPU时间片。3)运行(RUNNING):CPU选中该线程,执行run()方法逻辑。5)终止(TERMINATED):run方法执行完毕或异常终止,线程生命周期结束。流转核心:新建→就绪→运行→(阻塞/就绪)→终止。4.sleep、wait、yield、join的区别?sleep:线程休眠指定时间,不释放锁,属于Thread类方法,休眠结束后重新进入就绪状态,可被中断。wait:Object类方法,必须在同步代码块中使用,主动释放锁,进入对象等待池,需要被notify/notifyAll唤醒,或者超时自动唤醒。yield:Thread类方法,让出当前CPU时间片,线程回到就绪状态,不释放锁,只是礼让,大概率同优先级线程先执行,不保证一定生效。join:让当前主线程等待子线程执行完毕,再继续往下执行,底层靠wait实现,会阻塞主线程。5.为什么wait必须在同步方法/代码块中调用?核心是为了避免线程死锁和数据错乱。wait的逻辑是:拿到锁→释放锁→等待唤醒。如果不在同步代码块中,线程没有获取对象锁,直接调用wait会直接抛出异常。另外,如果不加锁,会出现丢失唤醒问题:一个线程刚判断完条件不满足,还没执行wait,另一个线程修改条件并执行notify,这个唤醒信号就会丢失,导致第一个线程永久等待。二、线程安全与锁机制高频题6.什么是线程安全?线程不安全的根本原因?线程安全:多线程同时操作共享资源,不会出现数据脏读、覆盖、错乱的问题,结果和单线程执行一致。不安全根本原因:共享变量+多线程并发读写+没有同步控制,加上CPU的指令重排、缓存可见性问题,最终导致数据不一致。典型场景:多线程累加count变量,结果小于预期值。7.synchronized底层原理?偏向锁、轻量级锁、重量级锁区别?synchronized是JVM层面的内置锁,底层依赖对象头的MarkWord实现,锁状态会动态升级,只能升级不能降级。偏向锁:单线程频繁获取锁,没有竞争。JVM默认偏向当前线程,无需每次加锁解锁,开销极低。适合单线程重复抢锁场景。轻量级锁:少量线程交替抢锁,竞争不激烈。底层靠CAS自旋实现,不阻塞线程,空循环尝试抢锁,用户态执行,效率高。适合交替执行、无并发竞争场景。重量级锁:多线程同时竞争锁,CAS自旋失败升级为重量级锁。依赖操作系统互斥量,线程抢不到锁会阻塞,进入内核态,开销大。适合高并发竞争场景。锁升级流程:无锁→偏向锁→轻量级锁→重量级锁。8.synchronized和ReentrantLock的区别?1)锁实现:synchronized是JVM内置锁,原生支持;ReentrantLock是JDK代码层面实现的锁。2)可重入:两者都是可重入锁,同一个线程可多次获取同一把锁。3)公平锁:synchronized是非公平锁;ReentrantLock支持公平、非公平两种模式。4)可中断:synchronized不可中断,阻塞后只能等抢到锁或等待;ReentrantLock可响应中断,避免死等。5)条件唤醒:synchronized只有一个等待队列,notify只能随机唤醒一个;ReentrantLock可以绑定多个Condition,精准唤醒指定线程。6)性能:低竞争下两者差不多,高竞争下ReentrantLock性能更稳定。9.什么是可重入锁?为什么需要可重入?可重入锁指同一个线程可以多次获取同一把锁,不会自己阻塞自己。如果锁不可重入,会出现自身死锁。比如同步方法A调用同步方法B,两个方法用同一把锁,不可重入的话,线程拿到A的锁后,调用B时再次抢锁,会直接阻塞自己。synchronized、ReentrantLock都是可重入锁,底层靠记录线程持有锁的次数,每次加锁计数+1,解锁计数-1,计数为0才真正释放锁。10.volatile关键字的作用和局限性?核心作用两个:保证可见性、禁止指令重排,不保证原子性。可见性:一个线程修改volatile变量,会立刻刷新到主内存,其他线程能实时感知到最新值,解决缓存不一致问题。禁止重排:避免JVM和CPU为了优化性能打乱指令执行顺序,解决单例模式DCL的重排问题。局限性:无法保证复合操作原子性,比如i++、i=i+1,这类读写复合操作,volatile无法保证线程安全,只能用锁或Atomic原子类。11.CAS原理、优缺点以及ABA问题?CAS是无锁乐观锁机制,全称比较并交换。核心逻辑:预期值==内存值→更新新值,否则重试。优点:无锁、无线程阻塞,用户态执行,并发性能高。缺点:1)自旋重试消耗CPU,高竞争下频繁重试效率低;2)只能保证单个变量原子性,无法保证多变量;3)存在ABA问题。ABA问题:变量从A改成B,又改回A,CAS感知不到中间修改,会误判为无变化。解决方案:使用带版本号的原子类AtomicStampedReference,每次修改更新版本号,通过版本区分是否被修改过。三、JUC并发工具类高频题12.Atomic原子类原理?为什么比synchronized轻量?Atomic系列底层基于CAS+自旋实现原子操作,没有加重量级锁,不会阻塞线程。synchronized竞争激烈时会升级为重量级锁,线程阻塞、切换开销大;而Atomic全程用户态自旋,不涉及内核切换,开销极小,适合简单数值累加、更新场景。常用类:AtomicInteger、AtomicLong、AtomicBoolean、AtomicStampedReference。13.CountDownLatch、CyclicBarrier、Semaphore区别和使用场景?CountDownLatch倒计时计数器:一次性使用,主线程等待多个子线程全部执行完再继续。计数器减到0后无法重置。场景:批量任务并行执行,全部完成后汇总结果。CyclicBarrier循环栅栏:可循环复用,多个线程互相等待,全部到达栅栏点后再一起同时执行。场景:多阶段任务,每阶段所有线程就绪后再进入下一阶段。Semaphore信号量:控制并发线程数量,限流作用。可以设置许可数,限制同时执行的线程数。场景:接口限流、数据库连接池、资源抢占限流。14.ThreadLocal原理、使用场景及内存泄漏问题?ThreadLocal是线程本地变量,每个线程拥有独立的变量副本,线程之间互不干扰,解决多线程变量共享冲突问题。底层原理:每个Thread内部维护一个ThreadLocalMap,key是ThreadLocal对象(弱引用),value是存储的变量值。使用场景:存储线程独立上下文,比如用户登录信息、请求上下文、数据库连接,避免参数透传。内存泄漏原因:key是弱引用,GC会自动回收,但value是强引用。线程不销毁(比如线程池线程常驻),value会一直滞留内存,导致泄漏。解决方案:使用完后必须手动调用remove()清除数据。15.线程池核心参数及工作原理?核心七大参数:核心线程数、最大线程数、空闲超时时间、时间单位、任务队列、线程工厂、拒绝策略。工作流程:1)提交任务,当前运行线程数<核心线程数→新建核心线程执行任务;2)核心线程已满,任务进入阻塞队列排队;3)队列已满,当前线程数<最大线程数→新建非核心线程执行任务;4)线程数达到最大值、队列已满→触发拒绝策略。非核心线程空闲超时后会被回收,核心线程默认常驻。16.线程池四种拒绝策略?1)AbortPolicy:默认策略,直接抛出异常,终止任务提交;2)CallerRunsPolicy:谁提交谁执行,主线程自己跑任务,降低提交速度;3)DiscardPolicy:直接丢弃当前新任务,不报错、不处理;4)DiscardOldestPolicy:丢弃队列最旧的未执行任务,替换为新任务。17.为什么不推荐使用Executors创建线程池?Executors封装的线程池参数固定,容易出现资源风险:1)newFixedThreadPool、newSingleThreadExecutor:队列是无界队列,任务堆积过多会导致OOM内存溢出;2)newCachedThreadPool:最大线程数无限,高并发下会创建大量线程,耗尽CPU和内存资源。生产规范:必须手动通过ThreadPoolExecutor创建线程池,自定义队列大小、最大线程数、拒绝策略,规避风险。四、并发实战与疑难面试题18.什么是死锁?死锁产生的四个必要条件?如何避免?死锁:多个线程互相持有对方需要的锁,同时等待对方释放锁,彼此永久阻塞,程序卡死。四大必要条件(必须同时满足才会死锁):1)互斥:锁同一时间只能被一个线程持有;2)请求保持:线程持有一把锁,同时请求另一把锁,不释放已有锁;3)不可剥夺:锁只能持有者主动释放,不能被其他线程强行抢占;4)循环等待:多个线程形成环形锁等待链路。避免方案:破坏任意一个条件即可。最常用的是统一锁获取顺序、设置锁超时、使用可中断锁、减少嵌套锁。19.并发三大特性?各自问题如何解决?并发三大特性:原子性、可见性、有序性。原子性:操作不可拆分,要么全部执行成功,要么不执行。问题:多线程复合操作数据错乱。解决:synchronized、ReentrantLock、CAS原子类。可见性:一个线程修改变量,其他线程能实时感知。问题:CPU缓存导致变量更新不可见。解决:volatile、锁(加锁解锁会刷新主内存)。有序性:代码执行顺序和编写顺序一致。问题:CPU、JVM指令重排导致逻辑错乱。解决:volatile、内存屏障、锁。20.简单介绍AQS原理?AQS是JUC锁和工具类的底层核心,全称抽象队列同步器。核心是一个状态变量+一个双向阻塞队列。1)state变量:int类型,记录锁状态,0代表无锁,大于0代表有线程持有锁,可重入时state累加;2)CLH双向队列:抢锁失败的线程封装成节点,进入队列排队阻塞;3)抢锁逻辑:线程尝试CAS修改state加锁,成功则执行逻辑,失败入队阻塞;4)释放锁:线程执行完释放锁,唤醒队列中下一个排队线程继续抢锁。ReentrantLock、Semaphore、CountDownLatch底层全部基于AQS实现。21.公平锁和非公平锁的区别?各自优缺点?非公平锁:线程抢锁不排队,新线程直接尝试抢占锁,抢不到再入队。优点:吞吐量高,减少线程唤醒开销;缺点:队列老线程可能一直抢不到锁,出现线程饥饿。公平锁:严格按照排

温馨提示

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

最新文档

评论

0/150

提交评论