编码之道,道心破碎。

你好呀,我是歪歪。

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

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

题是这样的:

线程池提交一万个任务(每个任务都是各自独立的,互相没有依赖关系,每个任务的耗时 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,我还在摸索和思考。

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

相关推荐
Clay13 分钟前
nestjs实战 - buildadmin重构后端(初始化mock接口)
javascript·后端
巴厘猫14 分钟前
Java开发者新机遇:LangChain4j——在Java中构建LLM应用的利器
java·后端·langchain
科米米15 分钟前
demo01 ffmpeg 从usb uvc摄像头读取一张图片
后端
loop lee19 分钟前
【Spring】一文了解SpringMVC的核心功能及工作流程,以及核心组件及注解
java·后端·spring
巴厘猫20 分钟前
从零解锁Docker API,玩转容器的“幕后英雄”!
后端·docker·容器
Resean022322 分钟前
SpringMVC 6+源码分析(一)初始化流程
java·后端·spring·servlet·springmvc
MacroZheng32 分钟前
扔掉HttpUtil!看看人家的HTTP客户端工具,那叫一个优雅!
java·spring boot·后端
wenb1n33 分钟前
【MySQL】 配置谜团:为什么my.cnf配置了 max_connections=1000 却不生效?
后端
Freed&1 小时前
Elasticsearch 从入门到精通:术语、索引、分片、读写流程与面试高频题一文搞懂
大数据·elasticsearch·面试
码农脱贫1 小时前
记录一下公司真实的RabbitMQ 消费者消息挤压问题
后端