面试官:Java线程池的核心参数了解吗?谢飞机:会用new Thread就不错了!

44 阅读4分钟

第一轮:Java 核心与多线程

面试官:请介绍一下 Java 线程池的核心参数。

谢飞机:呃……核心参数?是不是就是 new Thread() 啊?我平时都是这么创建线程的,很高效!

面试官:……那你了解 ThreadPoolExecutor 的七个参数吗?

谢飞机:七?这么多?我知道有 corePoolSize 和 maximumPoolSize,一个是最小线程数,一个是最大线程数。哦对,还有 keepAliveTime,空闲时间,然后是 unit 时间单位,workQueue 工作队列,我还知道 ArrayBlockingQueue 和 LinkedBlockingQueue!

面试官:不错,那最后一个呢?

谢飞机:最后一个?是不是……线程工厂?ThreadFactory?

面试官:还差一个。

谢飞机:啊,我想起来了!RejectedExecutionHandler,拒绝策略!当任务太多,线程池处理不过来的时候就会触发。

面试官:很好,那你能说说常见的拒绝策略有哪些吗?

谢飞机:有 AbortPolicy,直接抛异常;CallerRunsPolicy,让调用者自己执行;还有 DiscardPolicy,直接丢弃任务;DiscardOldestPolicy,丢弃最老的任务,再尝试提交当前任务。

面试官:回答得不错。


第二轮:JUC 与并发容器

面试官:我们项目中经常用到 ConcurrentHashMap,你知道它是如何实现线程安全的吗?

谢飞机:嗯……它是分段锁嘛,Segment,每个 Segment 相当于一个小 HashMap,加锁的时候只锁对应的 Segment,不影响别的线程访问其他段。

面试官:那是 JDK 1.7 的实现。JDK 1.8 呢?

谢飞机:1.8?哦,那个版本我也用过。好像是用了 synchronized 和 CAS,对头节点加锁,链表或红黑树的时候用 synchronized 控制访问。

面试官:那 put 方法的大致流程能说一下吗?

谢飞机:先算 hash,找到桶位置,如果为空就 CAS 插入;如果不为空,就 synchronized 锁住头节点,然后遍历插入,最后判断是否需要转红黑树。

面试官:可以。那如果多个线程同时 put 到同一个桶,会怎样?

谢飞机:只有一个能拿到锁,其他的等着呗。

面试官:好。


第三轮:Spring 与分布式技术

面试官:Spring 中 Bean 的作用域有哪些?

谢飞机:singleton 单例,prototype 原型,request、session、application,还有 WebSocket 的作用域。

面试官:AOP 是怎么实现的?

谢飞机:动态代理!JDK 动态代理和 CGLIB。JDK 需要接口,CGLIB 是子类继承。

面试官:Dubbo 的负载均衡策略有哪些?

谢飞机:随机、轮询、最少活跃数、一致性哈希……我记得随机是默认的。

面试官:Redis 的持久化机制?

谢飞机:RDB 是快照,AOF 是日志追加。RDB 恢复快但可能丢数据,AOF 更安全但文件大。

面试官:MySQL 的索引失效场景?

谢飞机:like 以 % 开头、类型转换、函数操作、or 条件没都建索引、联合索引不满足最左前缀……

面试官:很好。今天先到这里,回去等通知吧。

谢飞机:好的好的,谢谢面试官!


答案详解

1. ThreadPoolExecutor 七大参数

  • corePoolSize:核心线程数,即使空闲也不会被回收(除非设置 allowCoreThreadTimeOut)。
  • maximumPoolSize:最大线程数。
  • keepAliveTime:非核心线程空闲存活时间。
  • unit:时间单位。
  • workQueue:阻塞队列,如 LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue。
  • threadFactory:自定义线程创建方式,便于命名和监控。
  • handler:拒绝策略,用于线程池饱和时的处理机制。

执行流程:提交任务 → 核心线程未满则创建核心线程 → 否则加入队列 → 队列满且线程数 < 最大线程数,则创建非核心线程 → 否则执行拒绝策略。

2. ConcurrentHashMap(JDK 1.8)

  • 放弃 Segment,采用 Node 数组 + 链表/红黑树。
  • 使用 synchronized 对链表头节点加锁,锁粒度更小。
  • CAS 保证初始化和新增节点的安全性。
  • sizeCtl 控制初始化和扩容状态。

3. Spring Bean 作用域

  • singleton:整个 Spring 容器共享一个实例。
  • prototype:每次请求都创建新实例。
  • request/session/application:Web 环境下的生命周期绑定。

4. AOP 实现原理

  • JDK 动态代理:基于接口,通过 Proxy 和 InvocationHandler 实现。
  • CGLIB:基于继承,生成子类并重写方法,使用 Enhancer。

5. Dubbo 负载均衡

  • RandomLoadBalance:按权重随机选择。
  • RoundRobinLoadBalance:轮询。
  • LeastActiveLoadBalance:优先选活跃数最少的。
  • ConsistentHashLoadBalance:相同参数请求落到同一台机器。

6. Redis 持久化

  • RDB:定时快照,性能好,恢复快,适合备份。
  • AOF:记录每条写命令,append-only,可配置 fsync 策略(always/everysec/no),更安全。

7. MySQL 索引失效场景

  • LIKE '%abc'(前导通配符)。
  • 对字段使用函数或表达式(如 UPPER(name) = 'ABC')。
  • 类型隐式转换(字符串字段传数字)。
  • OR 条件中部分字段无索引。
  • 联合索引未遵循最左前缀原则。
  • 数据分布极不均匀导致优化器放弃索引。