编码之道,道心破碎。

你好呀,我是歪歪。

前几天有个读者问了我两道面试题。

当时我正在外面跑步,看了一下题目,线程池相关。

题是这样的:

线程池提交一万个任务(每个任务都是各自独立的,互相没有依赖关系,每个任务的耗时 100ms),怎么定义线程池各个参数,服务器是 4 个核心每个任务都要调用外部接口获取数据,进行统计汇总后,写入到 MySQL 中,还需要对其中的每 100 个任务的执行结果是成功和失败等状态进行汇总统计。对于失败的任务该如何进一步处理?要求能够尽快的处理掉这 1w 个任务。

问题:

  1. 线程池参数
  2. 每个任务的执行的情况进行汇总
  3. 失败的任务该怎么进一步处理

题不算复杂,于是边跑步边想,也想到了个八九不离十的回答。

也不知道题目中的 1w 个任务的具体形式是什么,我这边就先假定是数据库中 1w 条待处理的数据吧。

首先,第一个问题,线程池参数如何设置?

从题目描述来看,因为涉及到外部接口调用,所以这个线程池处理的任务类型我们可以判定为是 IO 密集型的,涉及到较为频繁的上下文切换,核心线程数可以设置的多一点。

这个多一点,指的是相对于服务器的核心数。

题目中给了服务器是 4 核的,所以核心线程数我觉得可以设置为 8。

为什么是 8?

别问,问就是经验值。是拍脑袋拍出来的一个感觉八九不离十的值。

队列长度可以设置为 15000,大于待处理的任务数。

你说设置为 11000 行不行?

也行,只要你能一次性把你这 1w 个任务装到线程池里面去就行。

什么,你问我会不会有内存问题?

放心,我负责任的告诉你,这点数据对于 4C8G 的服务器来说,洒洒水。

如果面试官非得说内存装不下,怎么办?

也行,那你就把队列长度调整为 1000,然后把这 1w 个任务从数据库里面分页查询出来,一批批的处理。

我觉得这不是考点。

然后最大线程数也可以设置为 8,反正队列里面装不满,最大线程数也用不上。

关键参数就这些。

另外,这个第一题表面上是在让你回答出一个具体的线程池参数,但实际上它是想考什么,你仔细分析分析?

其实他想考的是你对线程池运行过程的理解。

然后,你在往已经算是"标准答案"的"线程池运行情况监控+参数动态配置"这个方向去回答。

第一题就算是拿下了。

然后第二小题,每个任务的执行的情况进行汇总。

也就是每执行完 100 个任务,进行一次数据统计。

这就是计数嘛,很简单。

这个题我理解是考察的一个参数在线程之间共享,也就是线程安全的问题。

线程安全的计数器,是啥?

AtomicInteger 这玩意不就是可以干这个事儿吗。

至于第三个问题:失败的任务该怎么进一步处理?

在实际的工作场景中,这也是非常常规的一个需要处理的问题。

由于任务是从数据库捞出来的,所以我们可以给任务加一个状态字段,来标记任务是否处理成功。

如果失败了,就把状态设置为失败。

现在失败的数据都记录在案了,数据都有了,结合你的业务场景,你想怎么处理就怎么处理啊。

如果是约好了可以重试,那你就直接捞出来重试。

如果觉得不方向,就把问问下游系统这批数据为啥返回失败,能不能直接重发。

只要这批数据被记录下来了,就都能结合业务场景进行制定处理方案。

跑完步之后,我就在手机上回复了:

当时还有另外一道题目,由于在手机上看代码不方便,密密麻麻一大堆,完全没有看的欲望,我就直接没看。

写文章的时候我把代码粘出来一看,就清晰多了:

这道题也算是经典问题了,考点是 synchronized 锁的对象。

这题应该是要一眼秒掉的。

你看看 increment() 方法有 synchronized 修饰。

在非静态方法上的 synchronized 锁,锁的对象是什么?

老八股了,得张口就来:锁的是当前实例,也就是"this 对象"。

那你再看看 main 方法里面,是不是搞了两个实例:instance1 和 instance2。

所以线程 A 使用 instance1 的锁,线程 B 使用 instance2 的锁,两个线程持有不同的锁,互不打扰,所以它们可以同时进入各自的 increment() 方法,操作 value++ 方法。

所以,就会出现两个线程直接输出 2 的情况。

找到问题点了,就可以对症下药。

比如这样:

public static synchronized void increment(){}

锁的对象就从 this 对象变成了类对象,两个实例就会使用同一个锁。

再比如这样:

csharp 复制代码
private static final Object lock = new Object(); // 静态共享锁

public void increment() {
    synchronized (lock) { // 所有线程使用同一锁
     
    }
}

也能实现 A,B 线程串行执行 increment() 方法的效果。

道心破碎

等等,上面的这些内容和这篇文章的标题"编码之道,道心破碎"有什么关系?

是的,目前为止,毫无关系。

但是我确实被这两个小问题给搞的"道心破碎"了。

第一个线程池的问题,是我一点点自我学习、是把源码翻了又翻之后、从多次实际工作中实践,最终慢慢掌握到的线程池使用之道。

第二个问题 synchronized 关键字。

关于这个关键字我也曾经深入过源码,研究过各种各样奇奇怪怪的面试题,背诵过无数版八股文之后,才算是对它略知一二。

花费了大量的时间和精力,看了很多书、很多网站、很多博客,才一点点的把这些知识点塞到了脑海中。

我才能在跑步的时候,思考出这个线程池的问题到底应该怎么去回答。

才能在看到 synchronized 的代码的时候,一眼看出锁有问题。

但是,当我把这两个问题扔给 AI 之后,我的道心破碎了。

比如线程池的这个题,它不仅分析的头头是道:

甚至还给出了完整的场景模拟的代码:

最后还给出了优化建议:

比我给出的答案更好,更全面,更高分。

只用了几十秒,就能得到我花了大量精力才学会,并融汇贯通的东西。

轻而易举就能获得我呕心沥血才学会的东西。

在一定程度上,这就是我多年打造出来的护城河。

现在我感觉它让我的护城河看起来浅的很可笑。

所以我是真的感到恐惧,恐惧到我开始抗拒。

看着 AI 编程的势头越来越猛,我甚至有时候觉得 AI 就不应该被发明出来。

我知道这是不对的,但是我确实有一段时间是这样想的。

以前,我想起一个有意思的技术话题就会去一边研究一边写,最后把它写出来。

现在,当我研究了一点,然后在把它写出来的,我就会觉得,没意思。

单纯就是觉得没意思,因为我写的这些东西,去问 AI 都知道。

我把它写出来可能要用一周时间,但是去问 AI,它几分钟就能给你一大段内容,并说得头头是道。

我找不到我写出来的价值在哪里。

这件事情让我想起了一个久远的事情。

当时我才毕业不久,工作不到一年时间,和公司的一个有多年开发经验的老同事聊天。

他当时说了一句话,我印象深刻,大概是这样的,几乎是原话:

SpringBoot 这种开箱即用的东西就不应该被发明出来,Spring 的 xml 配置确实复杂,但是我用了这么多年了,我已经背下来了,这就是我的护城河,现在 SpringBoot 倒好,约定大于配置,一下子就把护城河给我挖没了。

我当时刚刚入行不久,苦于 Spring 的复杂配置,每次都头疼。

后来 SpringBoot 框架来了,才算是救我于水火,我就是它的受益者。

所以对于他的说法,我当时觉得是"暴论",SpringBoot 这么好的东西,当然得用了。

在心里想得是:你不去拥抱 SpringBoot 这么好的东西,你就会被它淘汰。

后来的事情你也知道了,SpringBoot 脚手架全面挤占了原生 Spring 的开发市场。

现在,时代变化了,但是故事没变。

AI 就是上面场景中的 SpringBoot。

而我变成了那位"有多年开发经验的老同事"。

AI 迅猛发展的这几年,特别是近半年,编码的道心确确实实被 AI 搞破碎过,多年埋头苦干挖出来的护城河也确确实实被 AI 给搞浅了。

后来我通过拥抱 AI 的方式,进行了重建,重建之后更坚固了。

多年埋头苦干挖出来的护城河也确确实实可以让 AI 再次挖得更深。

当下,虽然我已经在努力拥抱,但实际上我知道只是非常浮于表面的拥抱。

至于怎么更好更深入的拥抱 AI,我还在摸索和思考。

以上就是我的一点困扰和思考,分享给你。

相关推荐
独立开阀者_FwtCoder17 分钟前
从卡顿到丝滑,AI 应用体验跃升的幕后推手是它!
前端·vue.js·面试
前端小巷子24 分钟前
跨标签页通信(一):BroadcastChannel
前端·面试·浏览器
前端付豪25 分钟前
微信支付风控系统揭秘:交易评分、实时拦截与行为建模全流程实战
前端·后端·架构
uhakadotcom25 分钟前
完了,AI中台比数据中台更短命
面试·架构·github
深栈解码28 分钟前
OpenIM 源码深度解析系列(四):在线状态相关存储结构
后端
前端付豪30 分钟前
微信视频号推荐系统揭秘:兴趣建模、多模态分析与亿级流控架构实战
前端·后端·算法
bcbnb32 分钟前
跨平台接口一致性调试实录:如何用Sniffmaster等多款抓包工具拆解一个偶发Bug
后端
深栈解码32 分钟前
OpenIM 源码深度解析系列(五):分布式在线状态管理的完整实现
后端
brzhang1 小时前
我写了个脚本,让AI每天自动看完热榜、写稿、配乐,还用我的声音读出来
前端·后端·架构
bobz9652 小时前
vscode 使用 trunk code
后端