面试官:Java线程池的核心参数了解吗?谢飞机:会用new Thread就不错了!
面试官:请坐,先简单介绍一下自己。
谢飞机:面试官好,我叫谢飞机,三年Java开发经验,精通CRUD,熟悉Spring全家桶,会用new Thread,哦不,是熟悉多线程编程!
面试官:(微微一笑)那我们开始吧。
第一轮:Java基础与并发编程
面试官:你说你熟悉多线程,那线程和进程的区别是什么?
谢飞机:这个我知道!进程是资源分配的最小单位,线程是CPU调度的最小单位。一个进程可以有多个线程,线程共享进程的内存空间。
面试官:不错,理解到位。那Java中创建线程的方式有哪些?
谢飞机:两种!第一种是继承Thread类,重写run方法;第二种是实现Runnable接口,然后传给Thread构造函数。
面试官:还有呢?
谢飞机:呃……还有Callable + Future?可以有返回值!
面试官:很好。那为什么我们平时推荐使用Runnable而不是继承Thread?
谢飞机:因为Java是单继承啊!我如果继承了Thread,就不能继承别的类了,耦合太高!
面试官:回答得很好。
第二轮:JUC与线程池
面试官:既然提到多线程,那说说什么是线程池?为什么要用线程池?
谢飞机:线程池就是提前创建好一堆线程,放着不用的时候就等着,要用的时候直接拿,避免频繁创建销毁线程带来的开销!还能控制并发数量!
面试官:说得不错。那Java中常见的线程池有哪些?
谢飞机:有FixedThreadPool、CachedThreadPool、SingleThreadExecutor……还有一个叫Scheduled的,可以定时任务!
面试官:那这些线程池底层都是基于哪个类实现的?
谢飞机:嗯……ThreadPool?ThreadPoolExecutor!对!
面试官:很好。那ThreadPoolExecutor的七个核心参数分别是什么?
谢飞机:七个?我记得有核心线程数、最大线程数、空闲时间、时间单位、任务队列……还有两个是啥?(挠头)
面试官:还有一个是线程工厂,另一个是拒绝策略。
谢飞机:对对对!线程工厂用来创建线程,拒绝策略就是任务太多处理不过来时怎么处理,比如抛异常、丢弃、调用者自己执行等等。
面试官:那如果核心线程数是5,最大是10,队列长度是100,现在提交了120个任务,会发生什么?
谢飞机:前5个直接执行,后面95个进队列,第101到120……这时候队列满了,就会创建新的线程,最多到10个,所以还能再处理5个,剩下15个……(支支吾吾)就……就拒绝了?
面试官:基本正确。
第三轮:Spring与分布式技术
面试官:Spring中Bean的作用域有哪些?
谢飞机:singleton、prototype,还有request、session、application,但后三个是Web环境下的。
面试官:AOP是怎么实现的?
谢飞机:动态代理!JDK动态代理和CGLIB。JDK基于接口,CGLIB基于子类。
面试官:Redis有哪些数据类型?
谢飞机:String、Hash、List、Set、ZSet!还会用String存JSON!
面试官:缓存穿透怎么解决?
谢飞机:加布隆过滤器!把可能存在的key先记下来,请求进来先查布隆,没有就直接返回,不打数据库!
面试官:Dubbo的负载均衡策略有哪些?
谢飞机:随机、轮询、最少活跃数、一致性哈希……
面试官:xxl-job怎么保证任务不重复执行?
谢飞机:呃……它有个调度中心,应该会锁一下吧……(语无伦次)
面试官:好的,今天先到这里。你的基础还可以,回去等通知吧。
谢飞机:好的好的,谢谢面试官!(心里默念:又一轮面试结束了,不知道能不能过……)
答案详解
1. 线程 vs 进程
- 进程:操作系统资源分配的基本单位,拥有独立的内存空间。
- 线程:CPU调度的基本单位,属于某个进程,共享进程的内存和资源。
- Java中通过
Thread或Runnable创建线程。
2. 创建线程的四种方式
- 继承
Thread类 - 实现
Runnable接口 - 实现
Callable接口 +FutureTask - 使用线程池(
ExecutorService)
推荐使用Runnable,避免类单继承限制,也更符合“组合优于继承”原则。
3. 线程池 ThreadPoolExecutor 七大参数
- corePoolSize:核心线程数,即使空闲也不会被回收(除非设置allowCoreThreadTimeOut)
- maximumPoolSize:最大线程数
- keepAliveTime:非核心线程空闲存活时间
- unit:时间单位
- workQueue:阻塞队列,如ArrayBlockingQueue、LinkedBlockingQueue
- threadFactory:线程工厂,用于创建新线程,可自定义命名
- handler:拒绝策略,常见有:
- AbortPolicy(默认,抛异常)
- CallerRunsPolicy(由调用者线程执行)
- DiscardPolicy(静默丢弃)
- DiscardOldestPolicy(丢弃队列最老任务)
4. 提交120个任务的执行流程
- 前5个任务 → 核心线程执行
- 接下来95个 → 进入队列(共100容量)
- 第101~110个 → 创建非核心线程执行(最大10线程)
- 第111~120个 → 队列满 + 线程数达上限 → 触发拒绝策略
5. Spring Bean作用域
- singleton:单例(默认)
- prototype:每次获取都创建新实例
- request/session/application:Web相关
6. AOP实现原理
- JDK动态代理:要求目标类实现接口,通过
Proxy.newProxyInstance生成代理对象 - CGLIB:通过继承目标类生成子类,重写方法实现代理,适用于无接口类
7. Redis数据类型
- String:字符串,适合缓存对象(JSON序列化)
- Hash:哈希,适合存储对象字段
- List:列表,适合消息队列
- Set:集合,去重场景
- ZSet:有序集合,排行榜场景
8. 缓存穿透
- 问题:查询不存在的数据,绕过缓存直击数据库
- 解决方案:
- 布隆过滤器:快速判断key是否存在
- 缓存空值:对不存在的key也缓存,设置短过期时间
9. Dubbo负载均衡策略
- RandomLoadBalance:按权重随机(默认)
- RoundRobinLoadBalance:轮询
- LeastActiveLoadBalance:最少活跃调用数
- ConsistentHashLoadBalance:一致性哈希,相同参数请求总到同一节点
10. xxl-job防重复执行
- 调度中心通过数据库锁(如
SELECT FOR UPDATE)保证同一任务在同一时间只被一个调度线程触发 - 执行器端也有幂等控制,防止网络重试导致重复执行