Android 高级工程师面试:Java 多线程与并发 近1年高频追问 22 题
文章目录学习建议基础层8 题#1 线程有哪些创建方式Android 里怎么选 ⭐标准回答面试官可能继续追问#2 线程有哪些状态如何转换 ⭐标准回答面试官可能继续追问#3 为什么 Android 主线程不能做耗时操作 标准回答面试官可能继续追问#4 synchronized 的原理是什么锁升级过程 标准回答面试官可能继续追问#5 volatile 的语义是什么能保证原子性吗 标准回答面试官可能继续追问#6 synchronized 和 volatile 怎么选 ⭐标准回答面试官可能继续追问#7 wait/notify 和 sleep 有什么区别 ⭐标准回答面试官可能继续追问#8 什么是线程安全Android 里如何保证 ⭐标准回答面试官可能继续追问进阶层7 题#9 ReentrantLock 和 synchronized 怎么选 标准回答面试官可能继续追问#10 ThreadPoolExecutor 七大参数是什么 标准回答面试官可能继续追问#11 线程池四种拒绝策略怎么选 ⭐标准回答面试官可能继续追问#12 ConcurrentHashMap JDK 8 实现原理 标准回答面试官可能继续追问#13 CountDownLatch 和 CyclicBarrier 区别 ⭐标准回答面试官可能继续追问#14 AtomicInteger 等原子类解决什么问题 ⭐标准回答面试官可能继续追问#15 Handler 为什么会导致内存泄漏如何修复 标准回答面试官可能继续追问核心层7 题#16 happens-before 规则有哪些 标准回答面试官可能继续追问#17 AQS 是什么ReentrantLock 如何依赖它 标准回答面试官可能继续追问#18 双重检查锁单例有什么问题如何正确实现 标准回答面试官可能继续追问#19 Kotlin 协程和 Java 线程池在 Android 怎么选 标准回答面试官可能继续追问#20 为什么废弃 AsyncTask现代替代方案 标准回答面试官可能继续追问#21 死锁如何产生怎么排查 ⭐标准回答面试官可能继续追问#22 OkHttp Dispatcher 线程模型是怎样的 标准回答面试官可能继续追问面试策略速查必背知识高频追问加分项容易踩坑完整链路一句通相关推荐学习建议目标层级建议初级掌握基础层 8 题主线程规则、synchronized/volatile 区别、线程状态工程联想看追问第 1 条中级通读全文进阶层能讲清线程池七大参数、CHM 桶级锁、Handler 泄漏成因与修复高级核心层加分项必答happens-before、AQS、DCL能串联「同步原语→线程池→协程→泄漏排查」完整链路基础层8 题#1 线程有哪些创建方式Android 里怎么选 ⭐标准回答常见四种Thread、Runnable、CallableFuture、线程池。裸new Thread难管控生命周期与数量工程上应优先Executor/ThreadPoolExecutor。面试官可能继续追问Android 里线程怎么选网络用 OkHttp 内置 Dispatcher图片用 Glide 线程池业务异步优先 Kotlin 协程 viewModelScope避免无限创建线程导致 OOM。为什么不推荐到处new Thread无线程复用、无队列背压高并发时创建销毁开销大且难统一取消。协程和线程池是什么关系协程是用户态任务调度底层常跑在线程池的少量线程上不是 1:1 替代关系。#2 线程有哪些状态如何转换 ⭐标准回答六种NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。等锁进BLOCKEDwait()/join()进WAITINGsleep()/带超时wait进TIMED_WAITING。面试官可能继续追问Android 里线程状态怎么排查排查 ANR 或线程卡死时用 Profiler 或jstack看主线程是否长期BLOCKED在锁或 IO 上。RUNNABLE一定在 CPU 上跑吗不一定就绪队列中也算RUNNABLE等时间片调度。主线程BLOCKED常见原因同步块里做 IO、等子线程join、或 Binder 同步调用阻塞。#3 为什么 Android 主线程不能做耗时操作 标准回答主线程跑 UI 事件循环Looper驱动MessageQueue耗时任务占住主线程会导致输入、动画、绘制无法及时处理出现卡顿甚至 ANR。耗时逻辑应丢到Executor、协程Dispatchers.IO或专用 HandlerThread结果回主线程更新 UI。面试官可能继续追问ANR 触发阈值是多少输入约 5s、广播 10s、前台 Service 20s不同场景有差异。子线程能直接update UI吗不能必须切回主线程Compose 也遵循主线程更新状态规则。#4synchronized的原理是什么锁升级过程 标准回答synchronized基于监视器锁Monitor字节码层有monitorenter/monitorexit保证互斥与可见性。JDK 偏向锁→轻量锁→重量锁逐级升级竞争加剧时膨胀为 OS 互斥量。面试官可能继续追问Android 里synchronized怎么用多线程写共享缓存、单例初始化时常用注意锁粒度避免在 UI 路径锁整个大对象。锁的是对象还是代码锁的是对象监视器实例方法锁this静态方法锁Class对象。和ReentrantLock最大区别synchronizedJVM 自动释放ReentrantLock可中断、可超时、支持公平锁与Condition。#5volatile的语义是什么能保证原子性吗 标准回答volatile保证可见性与禁止指令重排不保证复合操作原子性如i。适用单一状态标志位如「请求已取消」「配置已刷新」。面试官可能继续追问Android 里volatile怎么用DCL 单例常配合volatile防重排多字段一致性仍用synchronized或原子类。volatile和synchronized性能差多少无竞争时volatile更轻有互斥需求必须用锁或原子类。DCL 单例为什么需要volatile防new对象指令重排导致其他线程拿到未初始化完成实例。#6synchronized和volatile怎么选 ⭐标准回答要互斥改共享变量用synchronized或Lock/Atomic只发布单一可见状态用volatile。面试官可能继续追问Android 里synchronized和volatile怎么选「下载取消标志」可用volatile boolean「计数器累加」用AtomicInteger或锁单用volatile会丢更新。多个volatile字段能保证组合原子吗不能读写之间可能被其他线程插入需整体加锁。Kotlin 里还需要手写volatile吗Java 字段可用Volatile多数场景用协程/原子 API 更清晰。#7wait/notify和sleep有什么区别 ⭐标准回答wait/notify必须在同步块内调用释放锁并进入等待队列notify唤醒后需重新竞争锁。sleep不释放锁仅暂停当前线程指定时间。面试官可能继续追问Android 里还用wait/notify吗业务很少手写多用CountDownLatch、BlockingQueue或协程suspend但理解有助于读 JDK/框架源码。为什么wait要在while循环里防虚假唤醒被唤醒后应再检查条件。notify和notifyAll怎么选不确定哪个线程满足条件时用notifyAll避免饿死。#8 什么是线程安全Android 里如何保证 ⭐标准回答多线程并发访问下仍保持正确语义即线程安全。手段不可变对象、线程封闭主线程 UI、同步锁、并发容器、原子类。面试官可能继续追问Android 里如何保证线程安全RecyclerView适配器数据源若在后台改、主线程读需 Copy-on-Write 或主线程统一调度SparseArray非线程安全多线程应加锁或换ConcurrentHashMap。StringBuilder线程安全吗不安全多线程拼接用StringBuffer或局部StringBuilder不外泄。主线程算线程安全吗单线程内天然安全但 Handler 延迟任务交叉时仍可能踩共享状态。进阶层7 题#9ReentrantLock和synchronized怎么选 标准回答都能互斥。ReentrantLock支持可中断、尝试锁、公平锁、Condition多条件队列需手动unlock且最好在finally释放。synchronized语法简单、JVM 优化成熟。面试官可能继续追问Android 里ReentrantLock和synchronized怎么选简单临界区用synchronized需要超时获取或精细唤醒用ReentrantLock。公平锁会降低吞吐吗会严格 FIFO 排队减少插队高竞争下吞吐通常低于非公平锁。忘记unlock会怎样其他线程永久阻塞类似死锁必须try-finally释放。#10ThreadPoolExecutor七大参数是什么 标准回答corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler拒绝策略。任务先填满核心线程再入队队列满则扩到最大线程仍满则触发拒绝策略。面试官可能继续追问Android 自建线程池注意什么应显式命名threadFactory便于 Profiler 定位队列有界防 OOM。核心线程会回收吗默认不会allowCoreThreadTimeOut(true)可让核心线程超时回收。为什么 IO 密集和 CPU 密集池大小不同CPU 密集≈核数IO 密集可更大因线程多在等 IO 而非占 CPU。#11 线程池四种拒绝策略怎么选 ⭐标准回答AbortPolicy抛异常默认CallerRunsPolicy调用方线程执行起背压DiscardPolicy静默丢弃DiscardOldestPolicy丢队首再提交。面试官可能继续追问Android 里拒绝策略怎么选后台任务高峰时CallerRunsPolicy可减缓提交速度防雪崩关键任务勿用Discard应降级或持久化队列。OkHttp 用哪种策略Dispatcher 自定义队列与并发上限超额任务在队列等待而非简单拒绝。无界队列有什么问题任务堆积导致内存暴涨表现为卡顿而非立刻抛异常。#12ConcurrentHashMapJDK 8 实现原理 标准回答取消分段锁采用Node数组 链表/红黑树对桶头synchronized或 CAS 插入。sizeCtl控制扩容transfer多线程协助迁移。读大多无锁volatile保证可见。面试官可能继续追问Android 里ConcurrentHashMap怎么用多线程缓存映射可用 CHMkey 为 int 时可评估SparseArray省装箱。CHM 允许null键值吗不允许防歧义HashMap单线程场景才可以。和Collections.synchronizedMap区别CHM 桶级锁并发读性能远好于全表一把锁。#13CountDownLatch和CyclicBarrier区别 ⭐标准回答CountDownLatch一次性计数减到零唤醒等待线程常用于「等多路异步完成」CyclicBarrier可重用多线程到齐再一起走支持屏障动作。面试官可能继续追问Android 里 Latch/Barrier 怎么用启动打点、多接口聚合刷新可用 Latch周期性同步更常用协程async/awaitAll。Latch 计数能加吗不能只能减一次性语义。主线程await会 ANR 吗会主线程禁止await阻塞等待。#14AtomicInteger等原子类解决什么问题 ⭐标准回答基于 CAS 无锁更新单个变量避免synchronized重量级竞争。适合计数器、状态位、引用替换。面试官可能继续追问Android 里原子类怎么用统计曝光次数、限流令牌可用原子类复合逻辑仍需AtomicReference配合或加锁。CAS 会自旋浪费 CPU 吗高竞争下会此时锁可能更合适。LongAdder和AtomicLong怎么选高并发累加LongAdder分段降低竞争需要精确读取当前值用AtomicLong。#15Handler为什么会导致内存泄漏如何修复 标准回答非静态内部类Handler隐式持有外部ActivityMessage又持有Handler若延迟消息未处理Activity 无法回收。面试官可能继续追问Android 里 Handler 泄漏怎么修静态内部类 WeakReferenceActivity、页面销毁时removeCallbacksAndMessages(null)、优先lifecycleScope替代裸 Handler。主线程 Handler 也会泄漏吗会泄漏与是否主线程无关取决于消息是否持有 Activity 引用链。onDestroy里必须清消息吗使用了延迟/周期性消息时必须清纯即时消息通常随队列消化。核心层7 题#16happens-before规则有哪些 标准回答JMM 定义的可见性偏序程序次序、监视器锁、volatile写先于读、线程start/join、传递性。理解它才能解释「为什么 DCL 要volatile」「为什么synchronized退出后其他线程能看见最新值」。面试官可能继续追问Android 里理解 happens-before 有什么用读框架并发工具源码如ConcurrentHashMap、Handler同步屏障都建立在 happens-before 之上。和「时间上的先后」是一回事吗不是happens-before 是内存可见性保证不保证墙钟顺序。final字段发布安全吗正确构造后final字段对其他线程可见常用于不可变对象设计。#17 AQS 是什么ReentrantLock如何依赖它 标准回答AbstractQueuedSynchronizer用state CLH 双向队列管理获取/释放同步状态。ReentrantLock、Semaphore、CountDownLatch内部都基于 AQS 定制tryAcquire/tryRelease。面试官可能继续追问Android 里需要了解 AQS 吗虽不直接写 AQS但读MediaCodec、Camera等阻塞队列工具时有帮助。state为 0 表示什么锁未被持有ReentrantLock重入时state递增。共享模式和独占模式区别独占如锁共享如Semaphore允许多个线程同时通过。#18 双重检查锁单例有什么问题如何正确实现 标准回答DCL 意图减少synchronized开销但未volatile时可能因指令重排发布半初始化对象。正确写法volatile实例 同步块双重检查。面试官可能继续追问Android 里单例怎么实现更好更推荐枚举单例或Application级懒加载 依赖注入DCL 多见于老旧 SDK 与面试题。枚举单例为什么更好JVM 保证枚举实例唯一且防反射/反序列化破坏。Kotlinobject单例需要 DCL 吗不需要语言层保证线程安全懒初始化。#19 Kotlin 协程和 Java 线程池在 Android 怎么选 标准回答IO/计算任务优先协程lifecycleScope/viewModelScope自动随生命周期取消结构化并发避免泄漏。线程池适合 SDK 边界、Java 遗留模块、或需严格隔离线程名的场景如 Glide。面试官可能继续追问Android 里协程和线程池怎么选不要GlobalScope阻塞式 Java API 在协程里用withContext(Dispatchers.IO)包装而非主线程等待。协程能替代 Handler 吗延迟/切主线程可用delayDispatchers.Main与Choreographer帧同步仍可能用 Handler。一个协程等于一个线程吗不等于多协程可复用少量线程挂起时不占线程。#20 为什么废弃AsyncTask现代替代方案 标准回答AsyncTask线程池全局共享、串行/并行行为版本间不一致易泄漏 Activity且与生命周期脱节API 30 起废弃。面试官可能继续追问Android 里AsyncTask替代方案协程 viewModelScope、Executor 主线程回调、WorkManager做可持久后台任务。新代码禁止再引入AsyncTask。WorkManager和协程分工需保证执行、重启、约束网络/充电用WorkManager页面内短时异步用协程。老项目大量AsyncTask怎么迁移按边界逐步换协程统一在ViewModel层发状态避免在Activity内起任务。#21 死锁如何产生怎么排查 ⭐标准回答死锁需互斥、占有且等待、不可抢占、循环等待四条件。典型线程 A 锁m1等m2B 锁m2等m1。面试官可能继续追问Android 里死锁怎么排查jstack/Android Studio Profiler 看Found one Java-level deadlock预防锁顺序一致、超时tryLock、缩小锁粒度。线上优先从主线程阻塞与 Binder 同步调用链入手。数据库也会死锁吗会Room/SQLite 事务交叉更新可能死锁需重试或统一访问顺序。tryLock失败怎么处理降级、重试或上报避免无限等待。#22 OkHttpDispatcher线程模型是怎样的 标准回答Dispatcher管理就绪异步调用与ExecutorService最大 64 并发、每主机 5 并发可配置超额进队列等待。同步execute在调用线程执行。面试官可能继续追问Android 里 OkHttp Dispatcher 怎么理解理解它可合理解释「为何大量图片请求不会无限开线程」。Glide 另有独立池网络层不要与业务自建池混用同一无界队列。同步请求能在主线程吗技术上能但会 ANR/卡顿禁止主线程execute。如何与协程suspend配合用suspendCancellableCoroutine包装enqueue取消时call.cancel()。面试策略速查面试等级建议掌握初级★★★☆☆中级★★★★★高级★★★★★必背知识主线程规则、synchronized/volatile、ThreadPool 七大参数、CHM、Handler 泄漏、协程 vs 线程池、AsyncTask 废弃原因高频追问「volatile 能保证原子吗」「线程池队列满了怎么办」「Handler 怎么防泄漏」「协程和线程区别」加分项happens-before、AQS 与 ReentrantLock 关系、DCL 与 volatile、OkHttp Dispatcher 并发上限容易踩坑主线程sleep/wait/网络请求无界队列线程池 OOM非静态 Handler 泄漏用volatile做i新代码继续用 AsyncTask完整链路一句通并发题一条线主线程只管 UI 事件循环共享状态用 synchronized/volatile/原子类/CHM 保证可见与互斥耗时任务进线程池或协程 IO 线程结果回主线程页面销毁必须取消任务并清 Handler 消息泄漏与 ANR 从这条链路上排查。相关推荐HashMap、mutableMapOf 与 ConcurrentHashMap 完全指南Android 高级工程师面试Java 基础知识 近1年高频追问 22 题