面试官:Java线程池的核心参数了解吗?谢飞机:会用new Thread就不错了!
面试官:请坐,先自我介绍一下。
谢飞机:面试官好,我叫谢飞机,三年Java开发经验,擅长增删改查,哦不,是高并发、分布式系统设计。
面试官:嗯,那我们开始吧。
第一轮:Java 基础与多线程
面试官:你说你懂高并发,那我问你,HashMap 和 ConcurrentHashMap 有什么区别?
谢飞机:这个我知道!HashMap 不安全,多线程下会死循环;ConcurrentHashMap 是线程安全的,用了分段锁!JDK 8 后改用 CAS + synchronized 了!
面试官:不错,基础还行。那 ArrayList 是线程安全的吗?
谢飞机:不是!它就像菜市场,谁都能插队加元素,容易乱套。
面试官:那怎么让它线程安全?
谢飞机:可以用 Collections.synchronizedList() 包一下,或者直接上 CopyOnWriteArrayList,读多写少场景特别香!
面试官:还可以。
第二轮:JUC 与 线程池
面试官:说说 Java 线程池的核心参数有哪些?
谢飞机:呃……有 corePoolSize、maximumPoolSize、workQueue……还有 keepAliveTime,最后一个是 threadFactory 和 handler!
面试官:很好。那如果核心线程数满了,任务会去哪里?
谢飞机:先进队列!队列满了才创建新线程到最大线程数。
面试官:那如果队列没满,会不会创建非核心线程?
谢飞机:不会!除非用的是无界队列,比如 LinkedBlockingQueue,那就永远不创建非核心线程了……哎,等等,我是不是说反了?
面试官:……你继续。
谢飞机:啊,我的意思是,要看队列类型!如果是 ArrayBlockingQueue,满了才会扩容线程。
面试官:还行。那 submit() 和 execute() 有什么区别?
谢飞机:execute 没返回值,submit 返回 Future,可以拿结果或捕获异常!
第三轮:Spring 与 分布式
面试官:Spring 中 Bean 的作用域有哪些?
谢飞机:singleton、prototype,还有 request、session……反正 web 场景用得少。
面试官:AOP 实现原理?
谢飞机:动态代理!JDK 动态代理和 CGLIB。接口用 JDK,类用 CGLIB。
面试官:Redis 持久化机制?
谢飞机:RDB 是快照,AOF 是日志追加……但 AOF 太大了会重写!像压缩一样!
面试官:MySQL 的索引失效场景?
谢飞机:like 左模糊会失效,'%张三';还有类型转换,int 字段传字符串;最左前缀原则破坏也失效……
面试官:xxl-job 如何保证任务不重复执行?
谢飞机:呃……靠数据库锁?还是 zookeeper?不对,应该是调度中心控制……我线上只配过 cron 表达式……
面试官:……
面试官:今天就到这里,你的表现……还可以。回去等通知吧。
谢飞机:好的!等您电话,我手机24小时开机,连着充电宝!
参考答案详解
1. HashMap vs ConcurrentHashMap
HashMap:非线程安全,允许 null 键/值,多线程下 put 可能导致链表成环(JDK 7),扩容时死循环。ConcurrentHashMap:- JDK 7:分段锁 Segment,减少锁粒度。
- JDK 8:Node 数组 + CAS + synchronized(锁桶头节点),性能更好。
2. ArrayList 线程安全方案
Collections.synchronizedList(new ArrayList<>()):所有操作加 synchronized。CopyOnWriteArrayList:写时复制,读操作无锁,适合读多写少,如监听器列表。
3. 线程池核心参数(ThreadPoolExecutor)
corePoolSize:核心线程数,常驻内存。maximumPoolSize:最大线程数。keepAliveTime:非核心线程空闲存活时间。unit:时间单位。workQueue:阻塞队列,如ArrayBlockingQueue、LinkedBlockingQueue。threadFactory:创建线程的工厂。handler:拒绝策略(Abort、CallerRuns、Discard、DiscardOldest)。
执行流程:
- 线程数 < core → 创建核心线程
- ≥ core → 入队列
- 队列满 → 创建非核心线程直到 max
- max 也满 → 执行拒绝策略
4. submit vs execute
execute(Runnable):无返回值,异常会抛出。submit(Runnable):返回Future<?>,可判断是否完成。submit(Callable):返回Future<T>,可 get() 获取结果或异常。
5. Spring Bean 作用域
singleton:默认,IOC 容器唯一实例。prototype:每次获取都创建新实例。request:一次 HTTP 请求一个实例。session:一个 HTTP Session 一个实例。application:整个 ServletContext 生命周期。
6. AOP 原理
- JDK 动态代理:基于接口,
Proxy.newProxyInstance(),反射调用InvocationHandler。 - CGLIB:基于继承,生成子类,重写方法,使用 ASM 操作字节码。
- Spring 默认:有接口用 JDK,无接口用 CGLIB。
7. Redis 持久化
- RDB:定时快照,
save 900 1表示 900 秒内至少 1 次修改就触发。优点:恢复快,文件小;缺点:可能丢失最后一次快照后数据。 - AOF:记录每条写命令,
appendonly yes开启。三种模式:no(OS 刷盘)、everysec(默认)、always(每次写都刷)。AOF 重写:BGREWRITEAOF压缩命令,避免文件过大。
8. MySQL 索引失效场景
- 最左前缀原则破坏:联合索引 (a,b,c),查询条件跳过 a 或 b。
- 范围查询后索引失效:
where a=1 and b>2 and c=3,c 不走索引。 - 左模糊:
LIKE '%java'。 - 类型转换:
WHERE user_id = '123',user_id 是 int,隐式转换导致索引失效。 - 使用函数:
WHERE YEAR(create_time) = 2024。 - OR 条件:部分字段无索引。
- 数据分布极不均衡:如性别字段建索引,优化器可能放弃使用。
9. xxl-job 高可用与去重
- 调度中心集群部署,通过数据库锁抢占任务调度权。
- 执行器支持 failover 和 failfast 路由策略。
- 任务不会重复执行,因为调度中心统一协调,每个任务在指定时间点只会被分配给一个执行器。
- 若需手动防重,可在业务层加分布式锁(Redis 或 DB)。