一、这次问了什么
- 你们项目用到线程池了吗?主要用在哪?
- 金价实时变化,客户想在金价低于自己设定的价格时自动买入,你怎么设计?
二、线程池:就像提前安排好几个工作人员
假设要给 1,000 个员工发送通知。
一个人挨个发,比较慢;一下找 1,000 个人同时发,又可能把系统压垮。
线程池就像提前安排好几个工作人员:有人空下来,就从排队的任务中拿一个继续做。这样既能同时干活,又能控制人数。
项目里一般用在哪
- 批量处理数据:比如一批员工数据,分成几份同时处理。
- 同时查几个接口:如果几个查询互不依赖,可以一起查,最后把结果合起来。
- 导出报表、发送通知:这些事情比较耗时,可以交给后台处理,让用户先看到“处理中”。
这些是常见例子,要选自己项目里真正做过的来讲。
面试时怎么说
用过,主要用在【自己的实际业务】。比如批量处理数据,如果一条条处理会比较慢,我们就把任务分批,交给线程池同时处理。但不能无限制地开线程,否则数据库或者下游接口可能扛不住,所以会限制同时执行的数量。处理失败的任务也会记录下来,方便重试和排查。
如果继续追问,先记住三个问题:
- 人够不够? 线程太少处理慢,太多又可能把系统压垮,需要实际测试。
- 排队的人太多怎么办? 队列要有上限,满了要有明确处理,重要任务不能直接丢。
- 系统重启怎么办? 重要任务先存进数据库或可靠的消息队列,不能只放在内存里。
三、金价自动买入:先用一个例子想明白
假设客户小王设置:
金价低于 600 元/克时,帮我买 10 克,只买一次。
这里的数字只是方便理解,暂不考虑手续费。
系统要做的事情就是:记住小王的要求,盯住金价,符合条件就帮他买,最后告诉他结果。
第一步:把小王的要求存下来
数据库里记一条购买要求:
| 谁要买 | 低于多少买 | 买多少 | 当前情况 |
|---|---|---|---|
| 小王 | 600 元/克 | 10 克 | 等待购买 |
还可以记录什么时候到期,以及小王有没有取消。
这里先跟面试官确认一句:“我先按低于目标价就买,而且只买一次来设计,可以吗?”
第二步:获取最新金价,看看谁满足条件
最好由提供金价的平台在价格变化时主动通知我们;如果平台只能提供查询接口,就定时去查询,但可能错过短暂出现的低价。
例如金价从 605 元降到 598 元:
- 小王要求低于 600 元,满足条件。
- 小李要求低于 590 元,不满足,继续等。
如果客户很多,可以按目标价格整理这些购买要求,找出满足条件的那一批,避免每次都检查所有客户。
另外,小王刚设置时如果已经是 598 元,也应该立刻检查一次,不能非等到下一次价格变化。
第三步:先标记“正在买”,防止大家重复买
假设两台服务器同时发现小王可以购买,不能各自都帮他买 10 克。
可以规定:只有成功把“等待购买”改成“正在购买”的那台服务器,才能继续。 数据库要保证这次修改只能有一个成功,不能两台服务器都先查一遍,再各自修改。
同时,把接下来要执行的购买任务存下来。这样即使服务器重启,也能知道这笔购买还没处理完。
面试官如果问专业名词,这就是用“条件更新”争取处理资格,再通过保存任务避免中途丢失。
第四步:真正买之前,再看价格和余额
刚才看到 598 元,不代表现在还能按 598 元买。
假设准备付款时涨到了 602 元,就不应该直接买。要确认交易平台能保证按符合小王要求的价格成交,比如支持限价单,或者能暂时锁住报价。
只在自己系统里查一下价格,然后直接按市价下单,仍然可能买贵。
资金也一样:不能只看一眼余额够不够,还要先把本次购买需要的钱锁住,防止同时被其他订单花掉。买成功后扣款,明确失败后再退回可用余额。
第五步:记录购买结果
- 成功了:记下订单和成交价格,把要求改成“已购买”,通知小王。
- 明确失败了:记下原因,释放锁住的钱,再根据规则决定是否继续等待。
- 一直没收到结果:先记成“结果确认中”,去交易平台查,不能马上再买一遍。
最后一种最容易被追问:
就像付款时页面转圈,你不能因为页面没反应,就认定没付成功,再付一次。
每次购买都带同一个固定编号。再次查询或重试时沿用这个编号,让交易平台知道“还是刚才那笔”,并且需要平台支持按这个编号防止重复下单。这种“重复请求也只买一次”的处理,就叫幂等。
四、线程池在这里干什么
假设金价突然下跌,1,000 个客户同时满足条件。
不需要为每个客户一直开一个线程盯价格。系统统一收到价格后,找到这 1,000 笔购买任务,再安排固定数量的线程处理,剩下的先排队。
就像店里突然来了很多订单:工作人员数量有限,接一单、做一单,不能一下子无限加人。
但买黄金的任务很重要,要先保存任务,再安排线程去做。线程池负责控制同时做多少件事,数据库或可靠的消息队列负责把没做完的事记住。
五、面试时可以直接这样回答
我会先把客户设置的目标价、购买数量和是否只买一次存下来。系统收到最新金价后,找出符合条件的客户。
比如客户设置低于 600 元买 10 克,价格到了 598 元,就准备执行。执行前先把这条要求从“等待购买”改成“正在购买”,而且只允许一台服务器修改成功,防止重复买。购买任务也要保存,避免系统重启后丢失。
真正下单时,再确认能不能按客户要求的价格成交,以及余额是否足够。如果平台支持限价或锁价,就利用它保证成交价格。
购买成功后记录结果并通知客户。如果接口超时,先查询这笔订单到底成功没有,不能直接再买一次。每笔购买使用固定编号,配合交易平台的防重复能力,避免重复下单。
如果同时满足条件的客户很多,就用线程池分批处理,控制并发,避免把系统和交易接口压垮。
六、先记住这五句话
- 存要求:谁要买、多少钱买、买多少。
- 看金价:价格满足条件,就准备执行。
- 别重复买:同一条购买要求,只让一个任务执行。
- 别买贵了:看到低价不等于能按低价成交,要让交易平台保证价格。
- 没回消息先查结果:超时不等于失败,不能直接再买一次。