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

24 阅读3分钟

第一轮:Java基础与多线程

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

谢飞机:呃……线程池?是不是就是new Thread()然后.start()

面试官:……我们说的是ThreadPoolExecutor

谢飞机:哦!那个啊,我知道!有核心线程数、最大线程数、队列、拒绝策略!

面试官(点头):不错,那这些参数分别有什么作用?

谢飞机:核心线程数是常驻线程,最大线程数是最多能开多少线程,队列用来放任务,拒绝策略是干不完了就拒绝!

面试官:还行。那如果队列满了,会发生什么?

谢飞机:那就新开线程,直到达到最大线程数,再不行就触发拒绝策略,比如抛异常或者丢弃任务。

面试官:很好。


第二轮:JUC与并发容器

面试官:ConcurrentHashMap 是如何实现线程安全的?

谢飞机:它是分段锁,每个段独立加锁,这样多个线程可以同时操作不同的段。

面试官:JDK 1.8 呢?

谢飞机:呃……还是分段锁吧?

面试官:不对,1.8 改为CAS + synchronized了。

谢飞机:啊?那我记混了……

面试官:那你来说说 volatile 关键字的作用?

谢飞机:保证可见性!一个线程修改了,其他线程立刻能看到!

面试官:还有呢?

谢飞机:还能防止指令重排序!

面试官:不错。


第三轮:Spring 与分布式技术

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

谢飞机:singleton、prototype,还有request、session……

面试官:很好。那 singleton 是线程安全的吗?

谢飞机:是!因为只有一个实例!

面试官:如果这个 Bean 里有成员变量呢?

谢飞机:呃……那可能就不安全了?

面试官:对。那 Redis 做分布式锁要注意什么?

谢飞机:用 SETNX!还要设置过期时间!不然死锁!

面试官:如果业务执行时间超过过期时间呢?

谢飞机:呃……那我就续命!Redisson 有看门狗!

面试官:还行。最后,xxl-job 如何保证任务不重复执行?

谢飞机:它有个调度中心,通过数据库锁来控制……吧?

面试官:嗯,差不多。今天先到这里,你回去等通知吧。

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


答案详解

1. ThreadPoolExecutor 核心参数

  • corePoolSize:核心线程数,即使空闲也不会被回收(除非设置 allowCoreThreadTimeOut)。
  • maximumPoolSize:最大线程数,当队列满时,线程池会创建新线程直到达到此值。
  • workQueue:任务队列,如 LinkedBlockingQueueArrayBlockingQueue
  • keepAliveTime:非核心线程空闲存活时间。
  • unit:存活时间单位。
  • threadFactory:线程工厂,用于创建线程。
  • handler:拒绝策略,如 AbortPolicy(抛异常)、CallerRunsPolicy(调用者线程执行)等。

2. ConcurrentHashMap 实现原理

  • JDK 1.7:采用分段锁(Segment),每个 Segment 相当于一个 HashTable,减少锁竞争。
  • JDK 1.8:改为 CAS + synchronized,Node 数组加锁,锁粒度更小,性能更高。

3. volatile 关键字

  • 可见性:通过内存屏障保证变量修改后立即写回主内存,其他线程读取时从主内存刷新。
  • 有序性:禁止指令重排序,确保代码执行顺序与程序顺序一致。
  • 不保证原子性:如 i++ 操作仍需 synchronized 或 AtomicInteger。

4. Spring Bean 作用域

  • singleton:默认,IOC 容器中唯一实例。
  • prototype:每次获取都创建新实例。
  • request/session/application:Web 环境下的作用域。

注意:singleton Bean 不是线程安全的,若包含可变成员变量,需自行保证同步。

5. Redis 分布式锁注意事项

  • 使用 SET key value NX EX seconds 原子操作。
  • 设置合理过期时间,避免死锁。
  • 使用 Redisson 可实现自动续期(watchdog)。
  • 注意锁误删问题,value 应使用唯一标识(如 UUID)。

6. xxl-job 任务去重机制

  • 调度中心通过数据库行锁(for update)保证同一任务在同一时间只被一个调度线程执行。
  • 执行器集群部署时,通过任务 ID 和调度时间戳进行幂等控制。