- 博客(3317)
- 收藏
- 关注
原创 置顶导读|《2026 Python 爬虫零基础入门》怎么学?学完能做什么?
本专栏面向Python爬虫零基础读者,系统讲解爬虫核心原理与实战方法,由浅入深,涵盖 HTTP、数据解析、反爬机制与工程化实践,帮助你从入门到具备独立编写爬虫的能力。
2026-01-27 08:45:37
180737
2
原创 置顶导读|《Python爬虫工程化实战》专栏导读:从“脚本能跑”到“系统能交付”,零基础小白也能做出可部署的Python爬虫!(持续更新中)
我长期专注 Python 爬虫工程化实战,主理专栏 👉 《Python爬虫实战》 👈:从采集策略到反爬对抗,从数据清洗到分布式调度,持续输出可复用的方法论与可落地案例。内容主打一个“能跑、能用、能扩展”,让数据价值真正做到——抓得到、洗得净、用得上。
2026-01-21 15:45:40
180513
6
原创 线程池核心线程数配个 8 就完事了?我被这个问题坑了整整三年!
那是我工作第二年,赶一个促销活动上线,整个后端服务用的是 Spring Boot,线程池配置全靠"感觉"——核心线程数写了个8,最大线程数写了个20,队列容量1000。上线后的头两个小时,一切都挺正常。然后流量起来了。监控上的接口 P99 直接从 200ms 飙到了 8 秒,Kibana 日志里开始报,告警电话打到了组长那里。我当时的第一反应是:"是不是数据库慢查询?"查了半天,发现根本不是——是线程池满了,任务被无情地拒绝掉了。改了配置重新上线,把核心线程数临时调到50,才把火扑下去。
2026-11-08 08:00:00
91
原创 用了好几年 Executors,线上服务 OOM 炸了才知道这坑有多深?
说起来挺丢人的,这是我工作第二年的事。当时在做一个内部的报表系统,需要并发处理几批数据导出任务。我觉得自己挺懂线程池的——不就是嘛,10 个线程,固定的,稳得一批。代码上了测试环境跑得飞起,QA 也没发现问题,直接上线了。当时我盯着这行错误看了足足一分钟,脑子里第一反应是:不可能啊,我用的是"固定大小"的线程池,怎么会 OOM?后来排查下来,问题根源在于:newFixedThreadPool内部用的是一个无界队列,请求进来的速度远超处理速度,任务在队列里堆积了几十万条,内存直接撑爆。
2026-11-08 00:00:00
354
原创 线程池用了好几年,你真的选对过吗?
那是我入行第三年,一个电商项目大促前夕,CTO 突然跑过来问我:“你们后端用的什么线程池?我当时很自信地回答:“,弹性扩容,多好啊。然后第二天大促,服务器直接 OOM 宕机了。事后排查,发现短时间内请求暴涌,疯狂创建线程,内存被线程栈直接吃干净了。那次生产事故让我狠狠地补了一课,也是从那以后,我才真正开始认真研究这四种线程池的本质区别,而不是"能用就行"。这篇文章写给那些和我当年一样,线程池随手就new、觉得线程池只是个工具类的开发者。只会照着文档 copy 线程池代码。
2026-11-07 08:00:00
476
原创 线程池都用了这么久,你真的搞懂拒绝策略了吗?
那是一个周五下午快下班的点,正当我收拾东西准备溜的时候,手机叮地一声,报警信息来了。。说实话,那一刻我脑子里闪过的第一个念头不是"怎么修",而是"这个 tm 是什么东西"。我当时刚入行没几年,线程池的基本用法会,但拒绝策略这个东西,之前压根没重视过,觉得那是"边角料"。线程池配置不合理,任务队列堆满了,触发了默认的 AbortPolicy,直接把调用方的请求给炸了。从那以后,每次我做 code review 遇到有人用二话不说就往里扔任务,我都要问他一句:“你的拒绝策略配的啥?
2026-11-07 00:00:00
124
原创 你的线程池参数,真的配对了吗?CPU密集型和IO密集型傻傻分不清,小心服务崩给你看
那是一个周五下午五点半,眼看就要下班,突然钉钉炸了——生产环境 API 响应时间从正常的 80ms 飙升到了 12 秒,部分请求直接超时。我们第一反应是数据库慢查询,翻了翻 SQL 监控,没啥异常。然后看服务器 CPU,也才跑到 40% 左右,不算高。线程池满了,任务在队列里堆积。更让人哭笑不得的是,那个线程池当时配置的核心线程数是,也就是按 CPU 核数来的——这个配置方式我记得是以前写 CPU 密集型任务时抄过来的,结果被无意间用在了一个全是数据库读写、文件操作的 IO 密集型服务上。
2026-11-07 00:00:00
321
原创 线程协作这道坎,你真的迈过去了吗?——深挖 CountDownLatch 的使用场景与底层原理
那是某年双十一大促前三天,我们的数据预热任务出了问题。简单说,我们需要在系统启动时并发拉取十几个数据源的配置,等所有数据都就绪之后,再开放对外服务。当时写代码的同学用的是最朴素的方式——启多个线程,然后用 来"估算"数据加载完成的时间。你猜怎么着?测试环境跑得好好的,生产环境一上线,某几个数据源因为网络抖动,5秒根本不够。然后服务就"带着空弹夹"开炮了,缓存全是空数据,直接触发了一波穿透,数据库差点跪了。我当时盯着告警大屏,内心只有一个想法:这要是用 就不会有这个问题。这件事之后,我专门花了时间把 从
2026-11-06 16:36:06
468
原创 线程池队列还在瞎选?搞不清 ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue,迟早要背锅
我第一次真正意识到线程池队列选型这件事有多重要,是在一个大促活动期间。那天凌晨快两点,订单系统 CPU 告警,延迟飙升,日志里一堆,值班的同事打电话把我喊起来,我半睡半醒地翻代码,看到的是一个用默认无界构造的线程池——没有容量限制,任务堆积到几十万,内存直接顶满,GC 疯狂摇摆,整个服务雪崩。修完这个事故我才去认真翻了 JDK 源码和 Java 并发编程相关资料,也把这三个东西好好捋了一遍。说实话,这三个类名你在面试题里一定见过,但"背答案"和"真正知道什么场景选哪个"之间,差了一个生产事故的距离。
2026-11-06 07:00:00
466
原创 你写的异步代码,真的“异步“了吗?—— CompletableFuture 异步编排深度实战
大概是两年前,我接手了一个商品详情页的性能优化需求。需求很简单,就是商品详情接口太慢,P99 延迟跑到了 2 秒以上,用户投诉页面加载卡顿。我打开代码一看,好家伙——// 当时的"伟大"代码,我给你们还原一下// 查商品基本信息,50ms// 查库存,80ms// 查评论,120ms// 查卖家,60ms// 查推荐,150ms// ... 还有几个查询全部串行。每个接口各自跑各自的,最终耗时直接是所有接口的时间相加。
2026-11-06 00:00:00
636
原创 都说会写并发,BlockingQueue 你真的用对了吗?
㊗️本期内容已收录至专栏《Java核心实操(进阶版)》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~㊙️本期难度指数:⭐⭐⭐🉐福利: 一次订阅后,专栏内的所有文章可永久免费看,持续更新中,保底1000+(篇)硬核实战内容。
2026-11-05 16:18:55
408
原创 定时任务都用 XXL-Job 了,你真的不需要 DelayQueue 吗?
㊗️本期内容已收录至专栏《Java核心实操(进阶版)》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~㊙️本期难度指数:⭐⭐⭐🉐福利: 一次订阅后,专栏内的所有文章可永久免费看,持续更新中,保底1000+(篇)硬核实战内容。
2026-11-05 16:18:15
273
原创 用了三年 Java,你真的搞清楚集合框架的底层逻辑了吗?
说起来有点惭愧,我第一次在生产环境翻车,原因居然是因为一个集合用错了。那是我入职后参与的第一个项目,一个电商后台的订单导出功能。需求很简单:把数据库里查出来的订单数据拼成一个列表,然后导出 Excel。我当时脑子里只有一个念头——“用 List 存一下就行了”,然后就直接往里塞数据,塞了几十万条。结果你懂的——OOM(OutOfMemoryError),系统直接挂了。那天晚上我和同事一起排查到凌晨两点,最后定位到是我把查询结果一次性全量加载进了一个ArrayList,没有做分页,也没有用流式处理。
2026-11-01 00:00:00
335
原创 都 2026 年了,你真的搞清楚 HashMap 在 JDK 1.7 和 1.8 之间到底变了什么吗?
那是某年某月,一个凌晨三点的生产环境。我盯着监控大屏,CPU 飙到 100%,某个服务线程全卡死,日志里一堆,看得我头皮发麻。排查到最后,定位到的罪魁祸首是——几个线程同时往一个HashMap里写数据,触发了扩容,然后形成了死循环。对,你没看错。HashMap 在多线程扩容的时候,会形成链表死循环,然后 CPU 就永远转圈圈了,永不停止,堪称死亡螺旋。那是 JDK 1.7 的年代。后来升到 JDK 1.8,这个问题消失了,但并不是说 HashMap 就线程安全了——它只是换了一种方式"坑"你。
2026-11-01 00:00:00
365
原创 都说 Phaser 是最强同步器,你真的搞清楚它和那几个“老前辈“的区别了吗?
说起来有点丢人。我第一次在生产项目里用Phaser,是因为我把它和搞混了。那是一个数据处理平台,需要按"批次"分阶段处理几十万条数据——第一阶段清洗、第二阶段转换、第三阶段入库,每个阶段结束后要等所有线程都到达"检查点"才能推进下一步。我理所当然地想到了线程数是动态变化的,有些批次 8 个线程,有些 16 个,还有中途可能有线程任务提前完成不参与后续阶段……这下彻底傻眼了。然后我才去翻 JDK 文档,发现Phaser这个家伙一直在那儿,安安静静等着我。说实话,Java 并发包里的这几个同步工具——
2026-10-31 08:30:00
461
原创 多线程里用 HashMap,你真的清楚自己在玩火吗?
本文通过一次真实线上死锁案例,深入剖析HashMap在多线程环境下的三大核心问题:复合操作非原子导致数据丢失、size计数可见性问题引发扩容异常,以及JDK 1.7中因头插法引发的扩容死循环。结合底层源码与流程图,揭示其背后原理,并给出解决方案——推荐使用ConcurrentHashMap或加锁保护,强调在高并发场景下避免使用非线程安全的HashMap。
2026-10-31 08:30:00
634
原创 你写了三年多线程,真的搞懂 LockSupport 的 park / unpark 了吗?
记得有一年,我在做一个消息中间件的内部实现,任务是自己写一个轻量级的阻塞队列。当时年轻气盛,一上来就用notify()把整个逻辑堆上去了,跑起来也没什么问题。直到有一天,测试同学反馈说线程偶尔会"卡死"——队列里明明有数据,消费者线程就是不动。我在那儿 debug 了将近半天,加了各种日志,才发现问题所在:在某些极端的调度时序下,notify()在wait()之前先执行了,那次"叫醒信号"就彻底丢了,消费者线程陷入永久等待。notify()不会"记住"它发过的通知,如果接收方还没wait()
2026-10-31 00:00:00
398
原创 HashMap 都用了这么多年,你真的搞懂它的扩容机制了吗?
我记得那是某个周五下午,快下班了,突然线上告警:一个接口的 P99 延迟飙到了 2 秒,正常情况下它从没超过 80ms。我们第一反应是数据库,然后是缓存,然后是网络抖动……折腾了半个多小时,最后发现——是某个服务在启动后的第一批请求里,一个局部缓存用的HashMap触发了多次扩容,恰好碰上了高并发,把 CPU 打满了。那一刻我真的想骂人,但又骂不出来,因为那段代码是我自己写的。其实说到HashMap,我们几乎每天都在用,它就像空气一样存在,理所当然。但空气这东西,平时感知不到,一旦出问题,那才叫难受。
2026-10-31 00:00:00
593
原创 都2026年了,你还在用 Future.get() 傻等结果、阻塞主线程跑异步任务吗?
事情发生在我参与的一个电商后台项目里,需求不复杂——下单成功后,同时触发三件事:发短信通知用户、扣减库存、写一条操作日志。// 等待三个任务完成粗看没问题,并发执行嘛,挺好的。但上线没两天,压测一跑,线程全堵死了。问题出在哪?是阻塞的,如果短信服务网络抖动,卡了 30 秒,后面和压根没机会执行,整条链路就这么挂着。更要命的是,线程池里的所有调用线程全都在等get(),新请求进来就没线程可用——连环雪崩就这么来的。那次之后,我系统地把FutureFutureTask。
2026-10-30 14:00:00
497
原创 你真的搞懂 HashMap 的红黑树转换了吗?别让面试官一句话问懵了你
说实话,我第一次在面试中被问到"HashMap 的红黑树转换条件是什么"的时候,我当时的反应是——哦,链表长度超过 8 就转。然后面试官微微一笑,问了一句:“只要超过 8 就一定会转吗?我愣了大概三秒钟。这三秒钟让我意识到,我之前以为自己搞懂了 HashMap,其实不过是背了个半吊子答案,连门都没真正摸到。回去之后我翻了一晚上源码,才发现这个"红黑树转换"背后藏的东西,远不止一个阈值那么简单——里面有设计取舍、有概率计算、有空间换时间的工程哲学,甚至还能追到一篇统计学论文里的泊松分布。
2026-10-30 09:30:00
6
原创 HashMap 都用了这么多年了,你真的知道它底层在干什么吗?
说实话,我第一次被问到"HashMap 底层原理是什么"的时候,脑子里蹦出来的第一个词是——“哈希表”。然后面试官微笑着看着我,说:“然后呢?然后就没有然后了,我凉了。那是我工作第一年参加的一次内部技术晋升答辩,当时我已经用 HashMap 用了快两年,各种 put、get、containsKey 玩得贼溜,项目里数据缓存、字典映射、频率统计全都是它。
2026-10-30 09:24:12
33
原创 并发这么多年了,你真的搞懂 ConcurrentHashMap 在背后偷偷干了什么吗?
说来惭愧,我第一次意识到的重要性,是被一个线上 Bug 逼出来的。那是我工作第二年,负责一个电商平台的商品缓存模块。业务逻辑说来简单:用一个 Map 做本地缓存,存储商品 ID 到详情的映射,每隔几秒钟刷新一次。代码也不复杂,随手用了HashMap,本地测试跑得好好的。结果上线大促当天,QPS 一上来,日志里开始出现奇奇怪怪的,甚至有几次直接 CPU 飙到 100% 卡死——事后排查,HashMap在高并发put操作下出现了死循环(JDK 1.7 的经典问题)。
2026-10-30 00:45:00
57
原创 都说 ConcurrentHashMap 线程安全,你真的搞清楚 1.7 和 1.8 底层到底改了什么吗?
说实话,我第一次认真研究的源码,是被一次线上事故"逼"出来的。那是某年某月某个深夜,我们的一个统计服务突然出现了数据错乱。排查了半天,最终发现是一个同事在高并发场景下把HashMap当用了——这还不是最惨的,更惨的是,他以为什么版本都一样,结果在 JDK 1.7 的环境下触发了一个分段锁粒度控制不当的问题,最终数据写入出现了丢失。从那以后,我就把这块内容认认真真地啃了一遍。
2026-10-30 00:00:00
581
原创 【共创稿事节】六十秒的墙:一个录音转写 App 教会我的端侧 AI 边界
暑假那阵子,突然接到我外婆应旧病复发又住院了的消息,刚好我放那时候高温假马上来了,于是就我主动说起去陪几天床。然后事情起因是这样的:医生来查房,他们速度很快,站十分钟左右讲完就走——医嘱、检查安排、饮食禁忌,全靠脑子记。我在备忘录里记了三天,漏了两次关键的。当时想找个录音转写的 App,应用市场里翻了一圈:能用的全要订阅,按分钟收费,一小时十几块;免费的不给离线,录音要传到不知在哪的服务器。病房里这种录音,我是不太敢往外传的。我自己写鸿蒙,于是就起了自己写一个的念头。
2026-10-29 14:37:28
351
原创 都叫线程安全 Map,Hashtable、Collections.synchronizedMap、ConcurrentHashMap 到底差在哪,你还敢随手选吗?
刚开始写 Java 并发代码那几年,我对线程安全 Map 的理解相当朴素。业务里有多个线程读写一个HashMap?那就换成Hashtable。后来有人说Hashtable太老?再后来项目 QPS 上来了,又有人告诉我:别用 synchronizedMap,换,性能高。听起来挺合理。问题是,当你真正在线上碰到并发 Bug,就会发现事情远没有一句“性能更好”这么简单。我印象特别深的一类问题,是做接口调用次数统计。map是线程安全的。get()是线程安全的。put()也是线程安全的。
2026-10-29 08:30:00
571
原创 都说 CopyOnWriteArrayList 线程安全,为什么上线后还是能把人坑惨?
前阵子复盘一个订单系统的监听器问题,我又想起一类特别有迷惑性的代码:业务上不过是维护几组回调,启动时注册,运行时遍历,偶尔还会动态注销。最开始大家用ArrayList,后来接口报了,便顺手把类型换成。异常确实消失了,值班群也终于安静下来。结果等到订阅量变大、配置刷新变频繁,写入耗时和内存曲线又开始让人挠头。解决了遍历时被修改的问题,不代表所有并发问题、业务一致性问题和性能问题都会一起消失。一个集合能做到线程安全,已经很不容易;
2026-10-29 00:00:00
356
原创 都用上 Queue 了,还分不清 BlockingQueue 和普通队列,真敢让它扛并发吗?
做后台系统时,有个需求特别容易被低估:用户提交订单,接口先返回“已接收”,后台再慢慢调用第三方物流、发送通知或者生成报表。第一版往往写得很漂亮:来一个任务就塞进队列,工作线程从队列里取出来执行。代码没几行,联调顺利,测试环境也安安静静。直到活动流量一上来,监控里队列长度直线上升,接口响应忽快忽慢,进程内存像坐电梯,最后业务同学跑来问一句:“不是异步了吗,为什么还会卡?,或者在一个错误的位置调用了put()。没有容量上限的队列把压力藏起来;没有超时策略的阻塞又可能把入口线程也一并拖住。换成?
2026-10-28 17:51:53
494
原创 PriorityQueue 都用到线上了,你还把它当成“会自动排序的 Queue”吗?
这个东西,大部分 Java 开发应该都见过。哪怕平时业务代码里用得不多,刷算法题的时候也基本躲不掉:API 也简单得有点过分:看到这里,很容易产生一个朴素但危险的印象:老实讲,这恰恰是我觉得理解 时最容易掉进去的坑。它不是一个一直排好序的数组,也不是 换了个名字,更不是你 一遍就能按照优先级拿到全部元素的神奇容器。它真正干的事情其实非常克制:说人话就是,假设你经营一家急诊室。来了 100 个病人,你没有必要每进来一个人,就把 100 个人从最严重到最轻微重新排成整整齐齐的一列。你真正关心的是:只要这
2026-10-28 17:51:12
333
原创 项目里开了好几个并发坑之后,我才搞明白 Exchanger 到底该用在哪儿
事情要从两年前说起。那会儿我在做一个数据清洗管道的项目——大概的业务背景是:上游系统每隔几秒会推一批原始数据过来,我们这边要做格式转换、校验、聚合,然后交给下游写库。听起来挺平常,对吧?问题出在两个线程之间的"交接班"上。生产者线程攒了一批数据,消费者线程处理完了想领下一批,两边都在用各种拼凑,结果线程协调逻辑越写越复杂,锁越加越多,最后上线跑了三天,莫名其妙出现数据乱序、批次错位的问题。那个深夜我盯着日志,一行一行翻,突然想起 JDK 并发包里有个冷门但精妙的类——Exchanger。
2026-10-28 00:00:00
912
原创 你的接口还在被并发打爆吗?Semaphore 限流这件事,我们聊透它
说一个亲身经历:有一次我在做一个内容平台的后台服务,功能上线初期一切正常,但某天运营突然搞了个活动,流量峰值来了之后,告警就炸了。日志里全是数据库连接池耗尽的报错,线程堆栈里一堆BLOCKED,服务响应时间从几十毫秒飙到十几秒,然后直接超时挂掉。我当时就在想:这接口平时跑得好好的,为什么一来流量就不行了?后来定位下来,问题出在一个对第三方服务的调用上。那个接口本来就慢,偏偏没做任何并发控制,流量一来几百个请求全部堆在那,把线程池塞满,然后整个服务雪崩。那次事故之后,我开始认真研究限流这件事,
2026-10-27 08:30:00
818
原创 多线程都用了这么多年,你真的搞懂 CyclicBarrier 了吗?
记得有一年做一个数据中台项目,需要从五个不同的数据源并行拉取数据,然后做聚合计算。当时我图省事,几个线程各跑各的,拉完就往下走——结果聚合的时候,有的线程还没跑完,下游逻辑就已经开始用"半生不熟"的数据了。测试环境没问题,一到压测,数据错乱得一塌糊涂。后来那个夜晚我翻了两个小时源码,才真正搞清楚这个东西是干嘛的,以及它和我之前随手用的到底有什么不一样。说实话,这两个类放在一起,很多人(包括当时的我)第一反应是:不就都是"等一等"嘛,有啥区别?区别大了去了。
2026-10-27 00:15:00
528
原创 用了这么多年 ArrayList,你真的搞懂它是怎么偷偷“搬家“的吗?
那是一个周五下午快下班的时候(是的,故事往往发生在这种时候),我在给公司做一个批量数据处理的模块。逻辑不复杂:从数据库分批读数据,然后往一个ArrayList里塞,最后统一做处理。数据量不大,也就几十万条,我寻思这不是小菜一碟嘛。结果跑起来发现,某几次批次的处理时间会莫名其妙地拉长两三倍,完全没有规律。排查了一圈,GC 日志一看——好家伙,频繁的 Minor GC,堆里一堆byte[]对象在乱跑。最后定位下来,问题就出在那个ArrayList身上。
2026-10-26 20:03:17
455
原创 面试年年考、项目天天用,你真的搞懂 ArrayList 和 LinkedList 的区别了吗?
那是我接手一个老项目的第三周,凌晨两点多,手机突然震动——监控告警,服务内存飙高,GC 频率异常。我登上服务器,dump 了一份堆快照,用 MAT 分析了一下,发现一个超大对象链条:一个LinkedList,里面塞了将近百万条日志记录,每条记录是一个对象,整个链表把 JVM 堆硬生生顶了个对穿。前任开发的注释写着:「用 LinkedList 是因为要频繁插入,ArrayList 插入慢。他说的不完全是错的,但他对"频繁插入"的理解,可能和实际情况差了十万八千里。
2026-10-26 20:02:43
424
原创 接口明明加了限流,为什么高并发来了还是扛不住?计数器、滑动窗口、令牌桶、漏桶,你真的选对了吗?
做后端开发这些年,有一类问题特别有意思:平时看着没什么存在感,一到系统流量上来,立马就能让整个开发群热闹起来。接口限流就是其中之一。想象一下这个场景。你负责一个电商系统,最近产品搞了个限时秒杀活动。活动还没开始,大家在测试环境里跑得挺开心:接口响应正常,Redis 没什么压力,MySQL 查询也挺稳定。结果活动开始后,监控上的请求量突然往上蹿。Redis 的请求量明显增加。MySQL 连接池开始吃紧。部分接口响应时间从几十毫秒涨到几秒。用户疯狂刷新页面,前端超时后又发起重试。
2026-10-25 00:00:00
655
原创 Redis 分布式锁都写了这么多年,你还敢用 `SETNX + DEL` 保证业务安全吗?
做后端久了,总会遇到一种特别让人挠头的 Bug:代码单独运行好好的,单元测试也绿得发亮,一上多实例、加点并发,数据就开始表现得像有自己的想法。订单明明只提交了一次,却被重复处理;定时任务明明设置了“只能跑一个”,两个节点却同时开工;后台点一次“生成报表”,下载列表突然冒出两份一模一样的文件。我最早接触 Redis 分布式锁时,觉得思路简直不能更直白:往 Redis 放个键,放进去的人干活,其他人靠边排队,干完删键。看起来就像给办公室会议室门口挂一块“使用中”的牌子。
2026-10-24 00:00:00
678
原创 Redis 都用上了,你还分不清缓存击穿、缓存穿透和缓存雪崩,真敢扛大促流量吗?
假设这样一个场景:晚上八点,一场限时促销刚开始。监控上 Redis 的平均响应时间还挺漂亮,个位数毫秒甚至更低,可 MySQL 的活跃连接数突然往上窜,商品详情接口从几十毫秒拖到几秒,网关开始刷超时日志。群里有人问:“Redis 不是加了吗?怎么还把数据库打成这样?这句话,听着熟不熟?刚接触缓存时,很容易把它理解成给数据库套了件防弹衣:请求先查 Redis,没查到再查 MySQL,查到了写回 Redis。画图五分钟,代码十几行,单机测试也相当顺畅。
2026-10-23 00:00:00
402
原创 分布式锁都用上了,你还敢只写一个 SETNX 就上线吗?Redis、ZooKeeper、数据库到底该怎么选?
说起分布式锁,我以前也干过一件现在想起来有点尴尬的事。那会儿项目刚从单体服务拆成多实例部署,业务里有一段“扣减库存”的逻辑。代码原本跑得挺好,Java 里面加了个,本地压测也没出过什么乱子。后来为了扛活动流量,服务从 1 个实例扩成了 6 个。然后,事情开始变得有意思了。stock = -1stock = -2当时第一反应当然是:“不可能啊,我明明加锁了。再往下查就发现,这句话只对了一半。我的确加锁了。但我锁住的是某一台 JVM 里的线程。...01上那把锁,压根不认识02上的那把锁。
2026-10-22 00:00:00
506
原创 都写了这么多年 Java,你还在拿 HashMap 硬扛排序、把 TreeMap 当万能字典吗?
从底层数据结构、红黑树、哈希冲突、时间复杂度,到 Comparator 陷阱、线程安全和真实项目选型,彻底搞懂 TreeMap 与 HashMap 的区别。适合读者:Java 初中级开发者、准备面试的后端工程师,以及已经在项目里用过 Map、但还没真正吃透它的程序员。技术基线:Java 17+,以 Java SE 25 官方 API 文档和 OpenJDK 实现为主要参考。不知道你有没有遇到过这种场景。项目开发得好好的,某天产品突然找到你:“订单列表能不能按照创建时间排序?
2026-10-21 18:39:59
368
原创 synchronized 真的只是“加把锁”这么简单吗?一文拆透无锁、偏向锁、轻量级锁、重量级锁的升级全过程
说实话,我刚学 Java 并发那会儿,对的印象特别粗暴:不就是在方法或者代码块前面加个关键字吗?加了就安全,不加就翻车。那时候的我,天真得像刚进健身房就敢挑战 120kg 深蹲的新手,脑子里只有一句话:锁住!都给我锁住!这东西,表面上像一把锁,背后却是一套非常精细的“锁状态管理系统”。它不是上来就把线程往操作系统里一丢,然后大家排队哭着等。无锁、偏向锁、轻量级锁、重量级锁。
2026-10-21 09:45:00
329
原创 对象锁和类锁到底锁住了谁?难道 synchronized 真的会把整个类都“焊死”吗?
刚开始写 Java 多线程的时候,我对的理解非常朴素,朴素到有点可爱:只要一个方法前面加了,线程就会乖乖排队,程序就会稳如老狗。至于它到底锁的是谁、挡住的是谁、为什么有时候挡得住有时候又像没挡住一样——不好意思,脑子里只有四个字:应该可以。后来项目里真出了问题,我才发现这四个字非常危险。那天线上有个统计任务偶尔会算错数,日志看起来风平浪静,数据库看起来一脸无辜,代码里甚至还写着。当时我盯着屏幕,心里一阵发凉:哎哟,这不科学啊,我都上锁了,怎么还乱?
2026-10-21 00:00:00
151
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅