资讯详情

资讯详情

使用Java开发十年后,我重新思考了基础的重要性

零、十年前我把“基础”当成一门可以速成的功课——学会语法、背熟API、刷完设计模式就以为拿到了Java世界的通行证。直到写了十年CRUD、调了无数个线上故障、看过几套烂到让人失眠的代码之后我才意识到真正决定一个程序员能走多远的从来不是你掌握了多少框架的皮毛而是你愿不愿意回头把那些被跳过的基础一块一块重新砸实。我用Java养家糊口十年从SSH到Spring Cloud从JVM堆内存爆掉到并发接口被压垮每一次被问题逼到墙角最后救我的都不是某个神奇的新框架而是那些早就被我扔在脑后的底层知识。你越早承认基础重要你踩的坑就会越少这话听着像说教但它是用我十年的加班和凌晨的复盘换来的。身边不少人跟我有同样的错觉Java技术栈更新快今天学响应式明天研云原生好像后浪一来基础就成了老古董。可真到代码里见真章时撑住场面的一定是那些不变的东西——内存模型、数据结构、并发语义、编译过程、算法复杂度。框架是流沙基础是岩石。我用了十年才把这个道理咀嚼出味儿来。一、框架换了一茬又一茬只有基础让你“不慌”第一份工作做保险系统团队用SSH。我每天的工作就是写好Action、Service、Dao然后在XML里把它们串起来。那时觉得“框架就是一切”Struts的拦截器、Spring的IoC、Hibernate的懒加载谁能背得越熟谁就看起来越像个牛人。直到有一天业务要我把一个多表复杂查询从Hibernate改成原生JDBC我当时竟然连PreparedStatement怎么设参数都要查文档——那一刻我吓了一跳一个干了三年的Java程序员居然不敢写裸JDBC那件事像一根刺扎了我很久。后来我开始有意识地学习Servlet规范、理解HTTP协议、自己手写一个极简的MVC容器。做这些事情的时候我突然发现那些框架的“魔法”不过是包装与约定底层还是那些最朴素的Java语法、类加载、反射和代理。框架给你的是快感基础给你的是安全感安全感这个东西平时看不见等框架出了问题或者项目要换技术栈时你才会发现它是你最后的底牌。这些年我经历过Struts退场、Spring Boot称王、微服务大行其道再去看向他的新同事很多人张口闭口云原生却连一个线程池的拒绝策略都解释不清楚。技术潮流带走的是名词留下的才是一个程序员真正的含金量。我从不反对学新东西但我反对用学新东西来掩盖自己地基没打好的事实。地基不稳的人看起来跑得快其实跑不了多远就碎在某个坑里。二、JVM和内存每次线上故障都在逼我重修基础工作第五年我负责的一个高并发服务OOM了。当时我先看代码没看出来使劲查日志只发现一堆OutOfMemoryError却不知道是堆还是栈还是元空间出了问题。于是我习惯性地重启多加了点内存参数好了。但第二天又挂了业务方拍桌子我蹲在工位旁一脸愧疚。后来一个资深前辈把我拉到一边跟我说了很长一段话我至今记得核心意思线上故障是基础最好的老师只是学费贵了点。他教我怎么先拿jmap看堆用jstat观察GC为了定位G1的混合回收为什么跟不上我被迫去啃分区、SATB、RSet这些底层概念。那段时间我连睡觉都在模拟对象从年轻代到老年代的晋升。我重新翻开了《深入理解Java虚拟机》以前觉得它像天书只挑了垃圾回收器名字背一背。这次真的是一个类加载器一个类加载器去确认一条指令一条指令去理解字节码。我终于看懂了i在字节码层的消耗也理解了为什么String.intern()用不好会造成永久代泄漏。原来我在业务里毫不在意的每个小动作底层都在付出代价。那次之后我再也不敢说“调优就是加内存”这种话。更重要的是我理解了Java运行时的全貌类加载双亲委派机制不是为了炫技而是为了避免核心类被篡改JMM的那套happens-before规则不是学术概念而是锁和并发优化的起点。每一个看起来空泛的基础知识点都能在线上事故中找到它对应的尸体。不想收尸就要在平时把尸体解剖清楚。三、数据结构与算法不是用来面试的是用来设计模型的多数Java业务开发都活在集合框架的舒适区里HashMap一putArrayList一接后端跟数据库打打交道似乎就足够了。但一旦数据量变大或者对响应时间有了极致要求你立刻会感觉到基础功底的稀缺。我写过一个分页接口用户翻到第2000页的时候数据库明显脾气不好于是我在内存里做了排序和过滤但接口反而更慢了——原因很简单我用的是List.contains()做关联匹配时间复杂度O(nm)算一次要扫上百万次。后来我换成了HashSet把两次遍历降成一次接口瞬间快了几十倍。你可能会哈哈大笑这不是基本功吗是啊可就是这种基本功在真实项目里被无数高级工程师忽略。算法与数据结构在Java业务代码里不是用来堆名词的它们藏在每个微妙的设计决策中。从那时起我就养成了一个习惯每写一段涉及循环和查找的代码先问自己一句“时间复杂度是多少有没有更好的容器”。再后来我开始设计缓存、设计本地消息队列、设计规则引擎的匹配逻辑。看到同事用List实现了一个生产者消费者队列我就给他讲为什么用ConcurrentLinkedQueue比synchronized(List)好看到有人用String拼接做大量日志提醒他用StringBuilder他很不屑结果压测时那部分CPU成了瓶颈。你不懂底层的数据结构你就不知道自己写出的代码在机器上如何被残忍地执行。基础给了你一双看不见数据流动的眼睛能帮你提前在纸上杀灭隐患而不是等上线后才跪着道歉。四、并发编程基础的深水区最容易淹死“熟练工”如果你问一个写了十年Java的人觉得哪个部分基本功最值钱我大概率会说是并发编程。它需要操作系统、内存模型、线程调度、锁优化、CPU缓存等一串学科交叉在一起。我只用new Thread()写过执行任务后来用线程池出过很多不可思议的bug。印象最深的是有一次线程池满了我连续提交几十个任务结果每一个都卡住不动。我当时反复检查业务代码死活看不出死锁点。后来才发现我把“核心线程数”和“最大线程数”理解错了又用了一个无界队列导致线程数始终维持在核心线程数上而任务全是阻塞式调用互相占着“数据库连接”不放。原来我对线程池的认知只停留在配置参数却不懂它的调度模型和背压策略。我又被迫去翻了ThreadPoolExecutor的源码把execute()的三种情况一条条画出来这才把阈值、队列、拒绝策略之间的关系彻底打通。从那以后我给自己立了一个新的学习规矩Java并发包里的每一个工具都要去问两遍——它到底解决了什么问题以及它为什么这么设计。例如CompletableFuture是怎么让异步代码更可读的synchronized和ReentrantLock在底层锁膨胀路径上有何异同volatile的内存屏障又是如何阻止指令重排。搞懂这些之后我再看到系统卡顿、接口超时、数据不一致脑中浮现的自动是线程状态流转图而不只是“加个锁试试”的莽撞。十年里并发相关的线上事故是最神出鬼没的也是最考察真实功底的。你以为你在写Java其实你在跟操作系统和硬件寄存器打交道。你写下的每一行volatile和CAS都是一场向计算机科学底层致敬的仪式。没有基础你连仪式为什么存在都不知道更别说在危机时刻救火了。五、重新拿起编译原理与设计模式基础不是八股文很多Java开发者一听到“编译原理”就头大觉得那是搜索引擎工程师才需要了解的领域。可在一次排查一个类库冲突的bug时我真切体会到了不懂字节码和类加载的痛。两个jar包里有同一个类的不同版本运行时一会儿用这个实现一会儿用那个实现那个诡异程度比鬼故事还吓人。我整整排查了两天最后才想起可以用javap -verbose去反编译看类的常量池和方法签名。那一刻我惊觉编译原理不是一门远离实战的学科它本身就是工程排障的显微镜。设计模式也一样我早年背了二十多个模式后来在业务里只会硬套“工厂”“单例”把简单问题复杂化。直到我看了Spring源码、Netty源码才明白模式不是让你照猫画虎的模板而是让你理解前人为什么要在那个场景中绕个弯。一个简单的策略模式能消灭一大串if-else一个模板方法模式就能把公共流程固化成骨架。这些基础的设计思想让我重构了旧的支付系统把一个两千行的Service类切开变成一组小而清晰的类。代码没有增加一行可读性却成倍上升。基础不是背出来的是干出来、拆出来、改出来的。当年抄代码时感到的“啰嗦”或“绕”在我有足够经验后都变成了一种“精准的优雅”。你若能看穿一个框架里最核心的2000行代码你就再也不会被依赖路径的长短困扰你若能自己为简单的表达式解析写一个状态机你以后看任何规则引擎都会觉得亲切。基础一旦长在肌肉里它就是你的思维本身。六、技术之外基础还包含你对计算机世界的完整图景写了十年Java之后我发现基础已经不止于语言层面的语法和库它还包括网络、操作系统、数据库原理、缓存一致性的底层逻辑。Java程序员使用的Spring Boot是跑在Linux上的它的线程是靠操作系统的调度执行的它的NIO模型是网络栈的内核异步的它的数据一致性是离不开文件系统与分布式协议之间的博弈。我有一次排查“偶发超时”用arthas看线程栈发现线程卡在socketRead。代码在等一个HTTP响应但对方的服务并没有挂只是响应慢了几百毫秒。我学着用tcpdump抓包分析TCP重传理解了四次挥手的TIME_WAIT出现在哪里懂得了为什么连接池需要合理的空闲探测。Java程序员如果只懂Java那他其实根本搞不定任何一个真正复杂的Java系统。基础的体系化决定了问题在你脑海里是模糊的痛点还是清晰的地图。这几年我也开始面试别人发现一个明显的规律能快速定位问题的人未必背了很多框架但他们往往能把问题一层层拆到操作系统和网络层而只会背组件用法的人遇到任何异常都会先百度再复制粘贴重启。基础扎实的人遇到问题像在追查一部推理小说的线索有章法有节奏基础薄弱的人像在黑夜中用锤子敲开关每一下都声嘶力竭但都在盲人摸象。七、重读经典Java书我读出了十年前没有的滋味最近我又重新翻开了《Java编程思想》《Effective Java》和《Java并发编程实战》感触完全不一样。十年前看它们是为了考试为了面试为了在简历上多写一句“熟悉Java核心类库”现在看它们我时常会拍大腿“当初要是听它的就好了”举个特别小的例子《Effective Java》里告诫过不要用finalizer我早年没当回事结果生产环境里有个对象一直占用着非堆内存就是不释放害得元空间涨得快爆掉。后来我把finalizer改成显式资源清理方法问题迎刃而解。十年前的我看不清价值是因为我根本没经历过那种痛苦。基础并不像新框架那样给你即时的刺激感——它像一座花园得等到春夏经过才能闻到迟来的花香。我鼓励年轻程序员别急着追求知识面的“新”先啃几本啃不动的经典书把里面的代码亲手敲一遍然后做几个深入的小实验。那些看似“费时”的笨功夫恰恰会在未来某次重大事故中成为唯一救你的灵光。同时我不再认为基础是一堆“要么懂要么不懂”的二元结论。基础是一个随着经验不断重新理解的递归过程——当你解决过了一百个线程问题你再读对JMM的初章会觉得那章处处都是血的教训。基础像洋葱每一层都比上一层的味道更冲也让人流泪更多但正是这些眼泪换来你对整个系统的敬畏。八、程序员的一生都是一场基础重建的修行很多年轻的Java开发者跑来问我该学哪个微服务框架该不该转Go该不该追AI应用。我给出的建议跟技术无关先把你的地基挖深半米再去盖楼。这不是老生常谈的“打基础”而是一个简单的经济学逻辑地基决定了你的上限框架决定了你的下限。你多会一个框架也许能让你的月薪上涨两三千但决定你能不能在重大故障面前站出来力挽狂澜的还是你对JVM、内存、并发、网络与数据结构的理解深度。十年的Java生涯让我明白最骄傲的时刻不是学会了一个新框架、发了一篇技术博客而是某天凌晨我盯着监控图谱平静地说出“这是GC频次过高引起的毛刺调一下堆回收参数就好”——那种笃定全部来自当年亲手敲过的测试代码与翻阅过的底层源码。技术人的底气就是这种从底层传来的坚实回响。别怕基础枯燥别嫌它来得慢。成熟的程序员不是从不跌倒的人而是在每次跌倒后都听得见地基断裂声的人。我花了十年才敢说自己正在慢慢补课如果让我回到刚入行那一年我会把那本《深入理解Java虚拟机》当成枕边书而不是积灰的板砖。今天写这些不是想教训谁只是替那个曾沉迷在框架绚烂泡影中的自己做一次诚实的复盘。我们现在所处的Java生态已经无比庞大但最值得依赖的仍然是那一小撮稳定的底层知识。把每一种数据结构捣碎把每一个并发工具看穿把每一段字节码认认真真读通这些事如果你愿意在职业生涯中反复去做那么即使十年后Java消失你也能带着一套完整的思维框架从容走进任何一片新大陆。技术是河流基础是河床——河流改道不可避免但河床的走向决定了水最终能流多远。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →