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

30 阅读3分钟

第一轮:Java核心与多线程

面试官:谢飞机,你先说说Java中创建线程有几种方式?

谢飞机:两种!继承Thread类和实现Runnable接口。我还知道Callable+Future可以拿到返回值!

面试官:不错,那线程池的几个核心参数能说一下吗?

谢飞机:额……corePoolSize是核心线程数,maximumPoolSize是最大线程数,还有个队列……叫什么来着?LinkedBlockingQueue?

面试官:那keepAliveTime呢?

谢飞机:这个我知道!多余的空闲线程等待新任务的最长时间!超过就销毁。

面试官:很好,那如果队列满了怎么办?

谢飞机:那就……开更多线程?到maximumPoolSize为止。再不行……我就重启服务器!

面试官:……(记录:基础尚可,但理解不深)


第二轮:JUC与并发容器

面试官:HashMap不是线程安全的,你们项目里怎么解决的?

谢飞机:我们用ConcurrentHashMap!听说它分段锁,性能好!

面试官:JDK 1.8之后呢?

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

面试官:错了,1.8之后改用synchronized+CAS了。那CountDownLatch和CyclicBarrier的区别呢?

谢飞机:都是等线程执行完……那个,Cyclic可以循环,像操场跑步,跑完一圈再来一圈!

面试官:那CountDownLatch呢?

谢飞机:只能用一次,像倒计时火箭发射,点火后就不能再点了!

面试官:比喻还行,但技术细节欠缺。


第三轮:Spring生态与中间件

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

谢飞机:singleton单例,prototype每次新建,request和session是Web里的。

面试官:Bean的生命周期了解吗?

谢飞机:Spring创建→属性填充→初始化→使用→销毁。我看过源码,refresh()方法特别长!

面试官:那你项目里用RabbitMQ怎么保证消息不丢失?

谢飞机:生产者确认机制、持久化、消费者手动ACK!我都配置了!

面试官:Redis缓存穿透怎么处理?

谢飞机:布隆过滤器!还有缓存空值。

面试官:如果攻击者绕过布隆过滤器呢?

谢飞机:那就……加防火墙?或者让他穿透,反正我下班了!

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


答案详解

1. 线程池核心参数

  • corePoolSize:核心线程数,即使空闲也不会被回收(除非设置allowCoreThreadTimeOut)。
  • maximumPoolSize:最大线程数,当队列满时,线程池会创建新线程直到达到此值。
  • workQueue:阻塞队列,如ArrayBlockingQueue、LinkedBlockingQueue等。
  • keepAliveTime:非核心线程空闲时的存活时间。
  • RejectedExecutionHandler:拒绝策略,如AbortPolicy、CallerRunsPolicy等。

2. ConcurrentHashMap JDK 1.8优化

  • 放弃Segment分段锁,采用Node数组+synchronized+CAS实现锁粒度更细的同步。
  • 在链表长度超过8且数组长度大于64时,链表转为红黑树。

3. CountDownLatch vs CyclicBarrier

  • CountDownLatch:一次性,计数器不可重置,主线程等待多个子线程完成。
  • CyclicBarrier:可重复使用,所有线程互相等待,到达屏障点后一起继续执行。

4. Spring Bean生命周期

  1. 实例化(构造函数)
  2. 属性赋值
  3. Aware接口回调(如BeanNameAware)
  4. BeanPostProcessor前置处理
  5. 初始化方法(@PostConstruct或init-method)
  6. BeanPostProcessor后置处理
  7. 使用
  8. 销毁(@PreDestroy或destroy-method)

5. Redis缓存穿透防御

  • 布隆过滤器:快速判断key是否存在,减少对数据库的无效查询。
  • 缓存空值:对不存在的key也缓存一个空对象,并设置较短过期时间。
  • 接口层增加校验:如用户鉴权、参数合法性检查。
  • 限流降级:防止恶意请求压垮系统。