Java线程经典面试题及详细答案(实战版)_第1页
Java线程经典面试题及详细答案(实战版)_第2页
Java线程经典面试题及详细答案(实战版)_第3页
Java线程经典面试题及详细答案(实战版)_第4页
Java线程经典面试题及详细答案(实战版)_第5页
已阅读5页,还剩1页未读, 继续免费阅读

下载本文档

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

文档简介

Java线程经典面试题及详细答案(实战版)一、线程基础高频题1.说说进程和线程的区别?这是面试最基础的问题,核心记住一句话:进程是资源分配的最小单位,线程是CPU调度的最小单位。具体区别:资源占用:进程独立占用内存、堆、文件句柄等系统资源,开销极大;线程共享所在进程的堆、方法区资源,仅独有栈、程序计数器,创建和销毁开销极小。独立性:进程之间完全隔离,一个进程崩溃不会影响其他进程;线程共享进程资源,单个线程异常崩溃,会导致整个进程终止。通信方式:进程通信复杂,需要管道、socket、共享内存等机制;线程通信简单,直接读写进程共享的变量即可。切换成本:进程切换需要刷新页表、缓存,开销高;线程切换仅需保存少量栈和寄存器信息,效率极高。2.线程的生命周期有哪些状态?分别是什么场景?Java线程一共有6种状态,是JDK源码定义的,分别是:新建、就绪、运行、阻塞、等待、超时等待、终止。NEW(新建):线程对象创建完成,但还没调用start()方法,仅存在于内存,未和操作系统线程绑定。RUNNABLE(就绪+运行):包含两种状态,调用start()后进入就绪状态,等待CPU时间片;抢到CPU资源后进入运行状态,执行线程代码。BLOCKED(阻塞):线程等待获取synchronized同步锁,其他线程释放锁后,该线程会重新进入就绪状态。TERMINATED(终止):线程代码执行完毕,或异常终止,线程生命周期结束。3.start()和run()方法的区别?很多初学者会混淆这两个方法,核心区别:start():是开启线程的核心方法,会向操作系统申请创建新线程,由JVM调度执行run()方法,真正实现多线程并发,只能调用一次,多次调用会抛异常。run():只是一个普通的成员方法,直接调用只会在当前主线程中执行,不会开启新线程,可重复调用。简单总结:start()创建线程,run()执行业务。4.为什么不建议用stop()、suspend()终止/暂停线程?这两个方法都是废弃方法,核心问题是线程安全和资源释放问题。stop():强制终止线程,会直接释放线程持有的所有锁,导致数据操作中途中断,引发数据不一致问题,且不会执行线程收尾代码,资源无法正常释放。suspend():暂停线程但不释放锁,容易引发死锁。如果暂停的线程持有锁,其他线程无法获取锁,会一直阻塞,程序卡死。正确终止线程的方式:自定义布尔标记、使用interrupt()中断线程。二、线程核心原理(并发、锁)1.什么是线程安全?导致线程不安全的原因是什么?线程安全:多线程并发操作共享资源时,程序运行结果和单线程执行结果一致,不会出现数据错乱、脏数据。线程不安全的三大核心原因:共享变量:多个线程同时操作同一个共享资源(堆内存变量、静态变量)。原子性破坏:复合操作(i++、赋值+判断)不具备原子性,多线程下会被拆分、穿插执行。可见性、有序性问题:CPU缓存、指令重排导致线程间数据不可见、执行顺序混乱。2.讲讲volatile关键字的作用?能保证原子性吗?volatile是轻量级同步关键字,核心两大作用:保证可见性:一个线程修改volatile变量,会立即刷新到主内存,其他线程会清空本地缓存,从主内存重新读取最新值。禁止指令重排:通过内存屏障,禁止编译器和CPU对volatile变量的读写指令进行重排序,解决单例模式的指令重排问题。重点:volatile不能保证原子性。它只能保证单次读写的可见性,像i++、i=i+1这类读-改-写的复合操作,依然会线程不安全。volatile适用于状态标记、开关变量这类单次读写的场景。3.synchronized和Lock锁的区别?这是面试必问对比题,核心差异如下:底层实现:synchronized是JVM底层原生锁,基于对象头、监视器锁实现;Lock是Java代码层面的锁,基于AQS队列实现。锁的特性:synchronized是隐式锁,自动加锁、自动释放锁;Lock是显式锁,需要手动lock()加锁、unlock()释放锁。等待机制:synchronized阻塞等待不可中断;Lock可响应中断、可限时等待,灵活性更高。锁类型:synchronized默认非公平锁,不可修改;ReentrantLock可自由切换公平/非公平锁。条件唤醒:synchronized只有一个wait/notify唤醒机制;Lock可以创建多个Condition,精准唤醒指定线程,效率更高。日常开发:简单同步用synchronized,高并发、灵活控制场景用Lock。4.什么是死锁?死锁产生的四个必要条件?如何避免?死锁:多个线程互相持有对方需要的锁,同时等待对方释放锁,所有线程永久阻塞,程序卡死。死锁四大必要条件(必须同时满足才会产生死锁):互斥条件:锁资源同一时间只能被一个线程持有。请求与保持:线程持有已有锁,同时请求新的锁资源。不可剥夺:已持有的锁不能被其他线程强行抢占,只能主动释放。循环等待:线程之间形成锁资源循环依赖。避免死锁的核心:破坏任意一个必要条件即可,常用方案:统一锁的获取顺序,杜绝循环等待;使用限时锁、可中断锁,避免永久阻塞;减少锁嵌套,尽量只持有一把锁。三、线程池高频面试题(重点)1.为什么要用线程池?直接newThread不好吗?直接创建线程弊端非常多,生产环境绝对禁止手动newThread,线程池核心优势:降低开销:线程创建、销毁开销大,线程池可复用线程,避免频繁创建销毁的资源消耗。控制并发量:限制最大线程数,防止无限创建线程导致CPU爆满、OOM内存溢出。统一管理:线程池统一调度、监控、管理线程,支持定时、延时、批量执行任务。提高响应速度:线程预热后,任务到来可直接执行,无需等待线程创建。2.线程池七大核心参数?以ThreadPoolExecutor为例,七大参数是面试核心,必须熟记:核心线程数corePoolSize:线程池常驻线程数,即使空闲也不会被回收。最大线程数maximumPoolSize:线程池能容纳的最大线程数量。空闲存活时间keepAliveTime:非核心线程空闲后的超时回收时间。时间单位unit:存活时间的单位(秒、毫秒等)。任务队列workQueue:存放等待执行的任务,常用阻塞队列。线程工厂threadFactory:创建线程的工厂,可自定义线程名、优先级。拒绝策略handler:任务队列和最大线程数都满时,触发的任务拒绝策略。3.线程池任务执行流程?口诀:先核心、再队列、后最大、再拒绝接收新任务,判断当前线程数是否小于核心线程数,是则直接创建核心线程执行任务;核心线程已满,判断任务队列是否未满,是则将任务存入队列等待;队列已满,判断当前线程数是否小于最大线程数,是则创建非核心线程执行任务;线程数达到最大值、队列已满,触发拒绝策略。4.四种拒绝策略分别是什么?AbortPolicy(默认):直接抛出异常,中断任务提交,适合关键任务。CallerRunsPolicy:谁提交任务谁执行(主线程执行),不抛异常、不丢弃任务。DiscardPolicy:直接丢弃当前新任务,不报错、不执行。DiscardOldestPolicy:丢弃队列中最旧的等待任务,执行当前新任务。5.为什么不推荐Executors创建线程池?阿里开发手册明确禁止使用Executors工具类创建线程池,原因是存在OOM风险:newFixedThreadPool、newSingleThreadExecutor:任务队列为无界队列,任务堆积过多会耗尽内存,触发OOM。newCachedThreadPool:最大线程数为Integer最大值,高并发下会创建大量线程,导致CPU爆满、内存溢出。生产环境必须手动创建ThreadPoolExecutor,自定义参数,规避风险。四、线程通信与并发工具类1.wait、notify、notifyAll的区别和使用注意事项?这三个方法是Object的方法,必须在synchronized同步代码块/同步方法中使用。wait():让当前线程释放锁,进入等待池,等待被其他线程唤醒。notify():随机唤醒一个等待该锁的线程。notifyAll():唤醒所有等待该锁的线程,由JVM竞争锁资源。注意事项:日常开发优先用notifyAll(),notify()随机唤醒容易导致线程永久等待,出现程序卡死。2.sleep()和wait()的核心区别?所属类不同:sleep是Thread类静态方法,wait是Object类方法。锁释放不同:sleep休眠时不释放锁;wait等待时主动释放锁。唤醒方式不同:sleep时间到自动唤醒;wait需要被其他线程notify/notifyAll唤醒。使用场景不同:sleep用于单纯延时;wait用于多线程通信、资源等待。3.CountDownLatch、CyclicBarrier、Semaphore的区别?CountDownLatch(倒计时计数器):一次性使用,主线程等待多个子线程执行完毕,计数器减到0后无法重置。适用场景:批量任务并行执行,全部完成后再执行主线程逻辑。CyclicBarrier(循环栅栏):可循环复用,多个线程互相等待,全部到达临界点后再统一执行。适用场景:多轮分段任务执行。Semaphore(信号量):控制并发线程数量,限流作用。适用场景:接口限流、资源抢占控制(如连接池限流)。五、高频进阶面试题1.什么是AQS?核心原理是什么?AQS(抽象队列同步器)是Java并发包的核心基础,ReentrantLock、CountDownLatch等工具类底层都是基于AQS实现。AQS核心原理:volatile修饰的state状态变量+FIFO双向阻塞队列state变量记录锁状态,0表示无锁,大于0表示已有线程持有锁;竞争锁失败的线程,会封装成节点存入双向队列,阻塞等待;锁释放后,唤醒队列头部节点线程,重新竞争锁。2.可重入锁是

温馨提示

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

最新文档

评论

0/150

提交评论