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

42 阅读5分钟

第一轮:Java基础与多线程

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

谢飞机:嗯……线程池?是不是就是用来开线程的?我一般都直接 new Thread(),省事!

面试官:……那你至少知道 ThreadPoolExecutor 的七个参数吧?

谢飞机:七个?我记得有 corePoolSize、maximumPoolSize,还有……keepAliveTime,对吧?其他的……好像是个队列,叫 BlockingQueue,再后面我就记不清了。

面试官:还行,那你说说这几个参数的作用?

谢飞机:core 是核心线程数,minimum threads;maximum 是最大线程数,最多能开这么多;keepAliveTime 是线程空闲了多久就销毁;队列是用来排队任务的,先进先出。

面试官:基本正确。那 workQueue 满了之后会发生什么?

谢飞机:满了?那就继续加线程呗,直到 maximumPoolSize。再不行……系统崩溃?

面试官:接近了。其实是触发拒绝策略。你知道有哪些拒绝策略吗?

谢飞机:AbortPolicy?好像抛异常。其他的……CallerRunsPolicy?让主线程自己跑?

面试官:不错,还有两个呢?

谢飞机:呃……DiscardPolicy?扔了?还有一个是……DiscardOldestPolicy?扔最老的那个?

面试官:很好,这部分你还算掌握得可以。

第二轮:并发容器与JVM

面试官:ConcurrentHashMap 和 HashMap 有什么区别?

谢飞机:HashMap 不安全,ConcurrentHashMap 安全!

面试官:具体怎么实现线程安全的?

谢飞机:1.7 是分段锁,每一段一个锁;1.8 改成 synchronized + CAS,更轻量。

面试官:那 put 方法在 1.8 中是怎么加锁的?

谢飞机:对链表头或红黑树根节点加 synchronized 锁。

面试官:如果发生哈希冲突严重,会变成什么结构?

谢飞机:链表变红黑树,当长度大于 8 且容量大于 64。

面试官:很好。那 JVM 内存模型了解吗?

谢飞机:堆、栈、方法区、本地方法栈、程序计数器。

面试官:对象 new 出来放在哪?

谢飞机:堆里!引用在栈里。

面试官:GC 主要发生在哪个区域?

谢飞机:堆!特别是年轻代,Minor GC;老年代是 Full GC。

面试官:不错。

第三轮:Spring 与分布式技术

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

谢飞机:singleton、prototype,还有 request、session……不过我只用过前两个。

面试官:单例 Bean 是线程安全的吗?

谢飞机:是!……啊不是!如果有成员变量就不安全!

面试官:那怎么保证?

谢飞机:不用成员变量,或者加 synchronized,或者用 ThreadLocal。

面试官:还可以。Redis 用过吗?持久化机制?

谢飞机:RDB 是快照,AOF 是日志追加。

面试官:哪个更安全?

谢飞机:AOF!丢数据少。

面试官:那性能呢?

谢飞机:RDB 快!恢复也快。

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

谢飞机:like 左模糊、函数操作字段、类型转换、or 条件没都建索引……

面试官:最后一个问题:Dubbo 的负载均衡策略?

谢飞机:random?round robin?least active?

面试官:可以。今天就到这里,回去等通知吧。

谢飞机:好嘞!我回去就把 new Thread 换成线程池!

参考答案详解

1. ThreadPoolExecutor 七大参数

  • corePoolSize:核心线程数,长期保持运行的线程数量。
  • maximumPoolSize:最大线程数,允许创建的最大线程数量。
  • keepAliveTime:非核心线程空闲时存活时间。
  • unit:时间单位。
  • workQueue:任务队列,如 LinkedBlockingQueue、ArrayBlockingQueue。
  • threadFactory:线程工厂,用于创建线程。
  • handler:拒绝策略,当队列满且线程数达上限时执行。

拒绝策略

  • AbortPolicy:抛出 RejectedExecutionException。
  • CallerRunsPolicy:由提交任务的线程执行该任务。
  • DiscardPolicy:静默丢弃任务。
  • DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试提交当前任务。

2. ConcurrentHashMap 实现原理

  • JDK 1.7:采用分段锁(Segment),每个 Segment 相当于一个 HashTable。
  • JDK 1.8:改用 synchronized + CAS,对桶的头节点加锁,锁粒度更小。当链表长度 ≥ 8 且 table.length ≥ 64 时转为红黑树。

3. JVM 内存结构

  • 堆(Heap):对象实例存储区域,GC 主要发生地。
  • 虚拟机栈(Stack):方法调用、局部变量、操作数栈。
  • 本地方法栈:Native 方法服务。
  • 程序计数器:记录当前线程执行字节码的位置。
  • 方法区(元空间):类信息、常量、静态变量等。

GC 分类:

  • Minor GC:发生在年轻代。
  • Major/Full GC:发生在老年代,通常伴随整个堆的回收。

4. Spring Bean 作用域

  • singleton:容器中唯一实例。
  • prototype:每次获取都创建新实例。
  • request:每个 HTTP 请求一个实例。
  • session:每个 HTTP Session 一个实例。
  • application:整个 ServletContext 范围内共享。

线程安全问题:singleton Bean 若有可变成员变量,则非线程安全,需通过无状态设计、ThreadLocal 或同步机制解决。

5. Redis 持久化

  • RDB:定时快照,恢复快,但可能丢失最后一次快照后的数据。
  • AOF:记录所有写命令,通过重放恢复数据,更安全但文件大、恢复慢。

建议:生产环境可同时开启,重启时优先加载 AOF。

6. MySQL 索引失效场景

  • 使用 LIKE '%xxx'(左模糊)。
  • 对字段使用函数或表达式(如 UPPER(name) = 'ABC')。
  • 类型隐式转换(字符串字段传数字)。
  • OR 条件中部分字段无索引。
  • 最左前缀原则被破坏(联合索引未从左开始使用)。

7. Dubbo 负载均衡策略

  • RandomLoadBalance:按权重随机,默认。
  • RoundRobinLoadBalance:轮询。
  • LeastActiveLoadBalance:最少活跃调用数,适合响应时间差异大的场景。
  • ConsistentHashLoadBalance:一致性哈希,相同参数请求落在同一节点,适用于缓存场景。