生命周期与顺序缺陷分类指南:Cassandra 代码审查中的 44 类时序错误模式
【免费下载链接】cassandraOpen source transactional distributed database. Linear scalability and proven fault-tolerance on commodity hardware or cloud infrastructure without compromising performance.项目地址: https://gitcode.com/GitHub_Trending/cassa/cassandra
本篇指南面向从事 Cassandra(分布式数据库)补丁评审、代码走查与缺陷定位的开发者与审查者。文章以仓库
.claude/skills/targeted-review/references/categories/lifecycle-and-ordering.md为骨架,系统讲解组件生命周期与操作顺序相关的 44 类缺陷模式(F-01~F-44):从"监听器注册晚于事件产生"的丢失更新窗口,到"关停顺序颠倒导致的假活窗口",再到"异步清理未等待即进入下一阶段"的竞态。每一类都给出触发信号、代码形态(**Look for:**定位提示)与修复方向,并结合 Cassandra 仓库中 Gossiper、StorageService 等真实实现佐证。读完本文,你将获得一套可直接套用于任何分布式系统补丁审查的"生命周期时序缺陷检查清单"。
一、分类定位:何时加载本类目
该分类文件(lifecycle-and-ordering.md)是 targeted-review 技能下 11 个缺陷分类之一。其适用场景(Diff signals)非常明确:只要补丁中出现与组件生命周期、启动/关停顺序、异步任务可见性相关的改动,就应当加载本类目。
具体而言,补丁若包含以下任一形态,都值得逐条对照本文的 44 类发现(Findings)进行排查:
- 新增或调整
register*/addListener/subscribe/addObserver调用及其放置位置; - 修改构造函数或
init()/start()的调用顺序,或引入新的初始化阶段; - 修改
close()/shutdown()/stop()的调用顺序、排空(drain)循环或拆除(teardown)时序; - 新增管理端点 / 指标注册,或对应的反注册路径;
- 出现无明确截止时间的轮询循环(
while (!ready)、await*Until*、带条件重试); - 新增异步任务(
submit、schedule、Future、CompletableFuture),且其产生的状态可被其他模块观察到; - 条件就绪标志(
is started/initialized/ready守卫)、状态广播方法; - 修改 bootstrap / join / handshake / handoff / quarantine 序列;
- 后台线程的创建(尤其是构造函数或工厂方法内部);
- 静态初始化器 / 类加载时对配置或单例的求值。
分类目录入口见 categories/INDEX.md,其中列出了全部 11 个类目的快速扫描信号;本类目的完整定义、diff 信号与发现清单位于 lifecycle-and-ordering.md。
二、启动阶段:监听器注册与状态发布的顺序缺陷
启动阶段最常见的缺陷,是"先拍快照、后注册监听",或"异步任务已开始、监听器才接线"。这类问题在 Cassandra 这类事件驱动、多阶段启动的系统中极易出现。
F-01:监听器注册前已报告状态(丢失更新窗口)
组件先把当前状态报告给调用方,随后才注册事件监听器;在快照与注册之间的更新会静默丢失。
定位提示:同一数据源上出现getState()/getCurrentX()之后紧跟addListener(...)/subscribe(...)的序列——正确顺序应为先注册、再取快照。
F-02:异步操作已开始后才注册监听器
处理器 / 监听器在生产者已开始发出事件之后才接线;启动到注册之间的"空窗期"事件被永久错过。
定位提示:start()/submit()/connect()/kickOff()调用先于同一组件的addEventListener(...)/onComplete(...)/register(...)。
F-03:管理接口在长初始化末尾才注册
指标、REST 或类似管理面在多阶段初始化的最后一步才注册——在之前的各个阶段,运维人员无法观测或控制系统。
定位提示:管理端点 / 指标注册、HTTP 端点绑定被放置在start()/init()中多个重量级初始化步骤之后。
F-04:异步重建可见性窗口(可查询但未就绪)
组件在请求到达时即被标记为"可查询 / 可用",但底层数据结构仍在异步重建或填充中;查询在路由层成功,却在数据层失败或返回空。
定位提示:提交异步重建任务后立即setReady(true),或就绪状态由"已注册"而非"已完成"推导。
F-05:启动轮询循环无截止时间
轮询循环等待外部就绪条件(对端、文件、网络、下游服务)时没有超时或最大尝试次数保护;上游永不收敛时永久挂起。
定位提示:while (!ready) { sleep(...); }/await(...)/pollUntil(...)无 deadline 参数、无最大迭代次数、调用方无法中止。
F-18:两阶段初始化中就绪标志过早可见
isReady/started标志在异步初始化提交之后、完成之前即被置位;读者看到"ready"但底层对象仍在构建。
定位提示:this.ready = true;被放在executor.submit(initTask)/service.startAsync()之后,而不是任务完成回调内部。
F-34:以固定时长 sleep 代替显式收敛等待
启动决策基于Thread.sleep(常量)来等待外部状态收敛;若收敛慢于 sleep 时长,节点将基于过期/不完整状态行事。
定位提示:启动路径中出现Thread.sleep(N)后读取对端 / 成员 / 配置状态——应改用显式就绪信号、条件变量或带超时的轮询。
F-43:后台调度先于必需状态建立而触发
初始化任务由固定时长定时器门控,而非显式生命周期事件;可能在拓扑、schema 等必需状态建立之前触发。
定位提示:scheduleOnce(initTask, delay)模式——delay 只是"赌"前置条件已完成;应改用显式依赖 / 就绪事件。
F-44:异步设置完成前应用即报告就绪
服务在异步设置完成之前就发布running/ready状态,给调用方一个错误的初始化完成信号。
定位提示:ready.complete()/setStatus(RUNNING)被放在submitAsync(setup)之后,而非 setup 的完成回调内部。
三、构造函数与静态初始化:类加载期的时序陷阱
Java 类加载与构造阶段存在特有的时序缺陷:后台线程在字段赋值完成前启动、静态初始化器在配置就绪前求值、构造函数把this泄露给外部观察者。
F-08:后台线程先于所有者构造完成启动
构造函数启动一个立即读取this.someField的线程;若构造尚未结束,线程观察到未初始化的字段而崩溃或看到陈旧状态。
定位提示:构造函数体内、字段全部赋值完成之前出现new Thread(this::run).start()或executor.submit(this::work)。
F-15:静态初始化器在子系统配置前求值
static final字段在类加载时读取全局单例或配置,而调用方尚未填充这些配置;该常量在 JVM 生命周期内被冻结为陈旧(通常是默认)值。
定位提示:字段初始化器中出现static final X = SomeService.get*()/Config.read(...);类加载触发早于配置器运行。
F-16:静态初始化器中调度后台任务
周期性 / 定时任务从静态初始化器提交,随类首次加载而运行;目标执行器或运行时可能尚未初始化,引发启动竞态或 NPE。
定位提示:static {}块或静态字段初始化器中出现executor.scheduleAtFixedRate(...)/Timer.schedule(...)。
F-23:静态初始化器触发循环类加载而死锁
静态初始化器调用可能抛异常的启动方法;后续类访问重新触发初始化器,而它试图获取已被中断初始化持有的锁,导致死锁。
定位提示:static { ... Service.initialize(); ... }块中initialize()可能抛出,且任何线程可能在恢复前再次引用该类。
F-24:构造函数在构建完成前把this交给外部观察者
构造函数在全部字段赋值前将this注册给外部监听器、注册表或另一线程;观察者看到部分构造的对象。
定位提示:构造函数体内(尤其是 final 字段赋值之前)出现registry.register(this)/executor.submit(this::work)/bus.subscribe(this)。
F-28:初始化步骤依赖子类构造前被调用的虚方法
基类构造函数调用可覆写(virtual)方法,而子类覆写依赖尚未赋值的子类字段;调用返回陈旧默认值,关键步骤被跳过。
定位提示:超类构造函数 /init()中调用子类会覆写的虚方法。
F-29:字段初始化顺序——依赖字段声明在依赖源之前
一个static字段引用源码中更靠后声明的另一个static字段;初始化顺序导致依赖字段读到 null/0,后续调用常触发 NPE(如 logger 使用)。
定位提示:静态字段声明中,某个初始化器调用了文件更下方另一个静态字段上的方法。
F-30:Setter 触发读取未赋值字段的副作用
构造函数内调用的 setter 触发副作用(通知、重算),而副作用读取的是同一构造函数中更晚赋值的字段,产生 NPE 或错误派生值。
定位提示:构造函数中的字段 setter 触发变更通知 / 重算——应先赋值全部字段,再通知。
F-33:关停序列引用从未初始化的字段
close()/shutdown()解引用仅在初始化成功后才赋值的字段;早期失败路径上的关停抛出 NPE,掩盖了原始启动错误。
定位提示:close()/cleanup()路径上未加守卫的字段访问——用if (field != null)守卫或将字段初始化为安全默认值。
F-17:初始化完成前生命周期方法被调用
init()、工厂create()或注册步骤被穿插,使stop()、回调或查询方法能在构造与完整设置之间被调用,命中半成品状态而崩溃或静默空操作。
定位提示:init()设置的就绪标志放在run()内(而非构造函数)——run()开始时早期stop()被静默覆盖;或查询方法命中未初始化字段。
四、异步任务与调度:等待缺失导致的竞态
异步任务的核心风险是"认为异步工作已完成"(assuming async work is done when it isn't)。包括未等待的清理、未等待的写、自提交死锁与一次性调度永不重排。
F-12:异步清理未等待即进入下一操作
代码触发异步清理/关闭后立即开始下一阶段,与尚未释放资源或状态的清理竞态。
定位提示:closeAsync()/removeAsync()/ fire-and-forget 删除之后,同一方法内对同一标识符立即重建或重启。
F-27:异步写 / 初始化未等待即继续
调用方发起异步写 /submit/executeAsync()后不等待即继续;下一步假设操作已完成,产生错误结果或丢失写。
定位提示:被丢弃的Future/CompletableFuture返回值,尤其是在初始化、schema 更新或迁移代码路径上。
F-19:一次性调度任务从不重排自身
周期性刷新任务使用一次性调度,只更新一次状态后从不重排;首次执行后周期循环静默停止。
定位提示:scheduler.schedule(task, delay)(一次性)用于本应scheduleAtFixedRate/scheduleWithFixedDelay的场景;或任务体内缺少自我重排(re-arm)调用。
F-20:周期任务以 flush/返回值而非时间门控重排
周期循环根据刚完成工作的副作用返回值决定是否重排,而非始终按时钟重排;异常返回值静默中止调度。
定位提示:调度处理器底部出现if (worked) scheduleNext()——重排应无条件或绑定生命周期状态,而非绑定工作结果。
F-22:先提交执行器、后注册资源(竞态窗口)
资源先被提交给执行器,之后才登记进跟踪集合;并发完成可观察到条目缺失,丢弃清理或允许重复提交。
定位提示:executor.submit(task)后跟tracker.put(task.id, task)——注册必须先于提交,或由任务本人在让出前完成注册。
F-37:首个响应即移除监听器,而并发在途请求共享它
监听器 / 会话在首个响应时反注册,但并发在途请求共享同一监听器,在完成前丢失引用,后续事件被静默丢弃。
定位提示:当多个未完成请求可映射到同一id时,单响应回调内出现tracker.remove(id)。
F-39:有界执行器因任务自提交而死锁
有界执行器的任务向同一执行器继续提交工作;竞争下所有工作线程都阻塞等待队列空间,而唯一能释放槽位的正是它们自己。
定位提示:已在同一执行器运行的任务内调用executor.submit(...)——重构为独立执行器或使用非阻塞交接。
F-40:回调内的阻塞调用卡死唯一可完成它的线程
回调同步等待一个 future,而其完成需要正在运行回调的单线程阶段本身——阶段死锁。
定位提示:完成处理器、RPC 处理器或单线程阶段回调内出现future.get()/await()。
F-41:订阅状态被非预期线程变更
共享订阅 / 成员状态在调用方(应用)线程上被直接修改,而后台线程预期独占它——产生撕裂读与调用间不一致的赋值。
定位提示:公开 API 方法直接变更订阅 / 分配 / 状态机字段,而非将变更入队给拥有它的线程。
F-42:初始化就绪检查使用陈旧代理信号
"就绪"条件由代理(如 pending 条目存在性)推导,而非直接比较 committed-vs-applied 计数器——在系统真正就绪前释放依赖操作。
定位提示:就绪检查测试间接副作用(队列大小、存在性标志),而非规范的"X 已通过 Y 应用"条件。
五、关停与拆除:顺序颠倒引发的假活、漏排空与半关闭
关停是生命周期缺陷的高发区:消费者先于消息源拆除、活性通道先于客户端传输关闭、排空只等队列不等生产者、终止标志与队列清空分步执行。
F-06:消费者先于其消息源被拆除
关停序列先停止消息处理器/消费者,再停止喂它的生产者或传输;在途消息到达半处置状态,产生错误或静默丢失。
定位提示:close()/shutdown()块中消费者/处理器先停、入站通道/队列/套接字/监听器后停——正确顺序通常是源优先。
F-07:后台线程初始化失败未通知派生线程
工作线程初始化失败,但派生线程未被通知;后续关停无限等待从未启动的工作线程。
定位提示:new Thread(...)/executor.submit(...)后跟thread.join()或关停中的 latch 等待,却没有回到派生者的异常通道。
F-10:关停期间存活探针仍在应答
存活响应处理器无条件应答"alive",不检查本地节点是否已开始关停;关停通知已广播后,对端仍将节点重新标记为存活。
定位提示:ping/heartbeat 处理器无条件发送肯定应答,未检查本地isShuttingDown/state == STOPPING标志。
F-11:服务停止顺序留下"看似下线但仍接受工作"的窗口
关停先停止活性/通告通道,再关闭客户端面传输;其间对端认为节点已消失,但它仍接受(随后丢弃)客户端连接。
定位提示:关停序列中gossip.stop()/failureDetector.stop()位于clientTransport.close()之前。
F-13:容量计数器在资源完全释放前递减
槽位/许可计数器在关联资源真正释放前递减为"空闲";并发接纳者看到空闲槽位,提交与清理竞态的新工作。
定位提示:slots.release()/count.decrementAndGet()位于 finally 块或完成回调中resource.close()/cleanup()之前。
F-14:关停排空只等队列、不等生产者
关停等待工作队列排空,但不等待向队列产出的执行器或上游阶段——关闭与在途写入竞态。
定位提示:queue.awaitEmpty()/ 基于队列的 latch 缺少对应的producerExecutor.awaitTermination()或关停路径上的生产者侧 join。
F-21:清理回调先于资源提交注册
清理/关闭回调在构造函数中接线,早于底层资源提交到长期存储;若半成品对象被丢弃,回调被孤儿化,清理永不执行。
定位提示:构造函数中出现addCloseListener(...)/onClose(...),且先于commit()/register(this)成功。
F-38:终止标志与队列清空分步执行
终止处理器分步设置"stopped"标志与清空工作队列;两步之间到达的消息引发断言失败或向半关闭状态提交工作。
定位提示:关停路径中this.stopped = true;后跟(或先于)queue.clear(),但缺少同时保护两者的临界区。
F-31:终止通知来自可重入的状态机
"变为 active / available"的通知从可多次发生的状态机转换中触发(如瞬态 resigned 状态),导致下游消费者收到误报。
定位提示:状态转换处理器中的 notify/event-fire 调用——应移到首次可达时只触发一次的真实一次性生命周期事件。
F-32:组件依赖晚于依赖它的组件初始化
依赖在已开始使用它的依赖组件之后才初始化;依赖组件静默跳过检查(如授权)或以默认行为运行。
定位提示:顶层 bootstrap 方法中start*()调用顺序——组件 A 依赖 B,但 B 更晚启动。
F-35:写屏障前取样快照(持久性丢失窗口)
持久化/flush 边界位置在写屏障或原子位置发布之前被采样;并发写可落于采样点之后却仍在 flush 批次内,截断时丢失。
定位提示:lastWritePos = currentPos()/snapshot()调用先于对应的barrier()/fence()/ 原子发布。
六、成员关系、迁移与就绪:集群语义相关缺陷
这类缺陷围绕 Cassandra 集群的成员生命周期(bootstrap/join/leave)、迁移替换与故障检测展开。
F-09:活性/身份在可服务前宣告
节点或组件在底层服务(传输、数据、依赖)就绪前即注册为健康/可用;客户端将请求路由给它并失败。
定位提示:健康检查注册、心跳发布或服务发现登记在启动中早于对应的 bind / 数据加载 / 依赖初始化步骤。
F-25:迁移/设置路径先加新条目再删旧条目
替换条目的迁移先添加新条目再删除旧条目;读者观察中间态同时看到两者,导致重复处理或二义查找。
定位提示:迁移助手中的add(new); remove(old);顺序——通常应为remove(old); add(new);或使用原子替换。
F-26:守卫反转时 bootstrap / 数据传输被跳过
bootstrap 守卫(if (!schemaPresent))在操作者未预期的情况下静默跳过数据传输阶段,节点以"已加入但为空"状态存在。
定位提示:任何由仅本地状态的单一布尔门控的bootstrap()/joinRing()/loadInitialState()调用——应与显式操作者意图结合。
F-36:首次观测不报告活性到达
故障检测器或到达报告器在对端首次观测路径上被绕过;检测器以零样本启动,永久认为对端不可达。
定位提示:首次观测路径跳过稳态路径执行的reportArrival()/recordSample()调用。
F-01/F-09 的集群实例:注册顺序与就绪广播
上述通用模式在 Cassandra 中有直接对应物:Gossiper的注册接口register(IEndpointStateChangeSubscriber)(见 Gossiper.java)必须在状态变更广播(如handleMajorStateChange,Gossiper.java)可能发生之前完成;否则节点加入/离开事件可能在订阅者就位前触发并被永久错过——这正是 F-02 所述形态。
七、Cassandra 仓库中的真实佐证:关停顺序与存活应答
分类文档描述的抽象模式在 Cassandra 源码中能找到具体实现。最典型的是F-10 / F-11 关停顺序与F-01 快照-注册顺序。
7.1 存活应答 vs 关停公告:F-10 的正面实现
Gossiper.stop()(Gossiper.java)在宣布关停前先置位shutdownAnnounced原子布尔:
public void stop() { EndpointState mystate = endpointStateMap.get(getBroadcastAddressAndPort()); if (mystate != null && !isSilentShutdownState(mystate) && StorageService.instance.isJoined()) { logger.info("Announcing shutdown"); shutdownAnnounced.set(true); addLocalApplicationState(ApplicationState.STATUS_WITH_PORT, StorageService.instance.valueFactory.shutdown(true)); addLocalApplicationState(ApplicationState.STATUS, StorageService.instance.valueFactory.shutdown(true)); // ...广播 GOSSIP_SHUTDOWN 消息给所有 liveEndpoints } if (scheduledGossipTask != null) scheduledGossipTask.cancel(false); }其注释(Gossiper.java)明确说明设计意图:"为避免与 ECHO 请求竞态,我们需要在宣布关停与响应心跳之间建立 happens-before 关系。一旦我们即将发送关停消息,就不应再响应心跳。" 这正是 F-10(存活探针在关停期间应答)的反向正确实现——shutdownAnnounced 标志即"本地是否已开始关停"的检查点。
与之配套,故障检测器裁决对端时,convict()(Gossiper.java)会先检查isShutdown(endpoint):已关停则markAsShutdown,否则markDead。这说明"先确认对端是否宣告关停、再判定其存活状态"在 Cassandra 中是一等公民逻辑,对应分类文档中 F-10 的"检查 isShuttingDown 标志后再应答"的修复建议。
7.2 关停顺序:F-11 的镜像参考
StorageService提供一组可供审查者对照的关停入口(StorageService.java):
stopGossiping()(L540-L556):停止 gossip,且显式警告"native transport 仍激活时禁用 gossip 是不安全的";stopTransports()(L644-L656):先停 native transport,再停 gossiper;stopClient()(L674-L682):依次unregister、Gossiper.stop()、MessagingService.shutdown()、等待一秒后Stage.shutdownNow();shutdownClientServers()(L668-L672):先setRpcReady(false)再stopNativeTransport()——先撤活性、再关客户端面,正是避免 F-11"节点看似下线但仍接受工作"窗口的编排。
审查补丁时,若看到新的关停路径把gossip.stop()/ 活性通道关闭放在客户端传输关闭之前,即可对照 F-11 标记为疑似缺陷;shutdownClientServers()中"先setRpcReady(false)(RPC_READY=false 通知对端不再接受请求)再停传输"的顺序,则提供了正确的参考实现。
7.3 初始化就绪标志:F-18 / F-44 的守卫样例
StorageService的isInitialized()(StorageService.java)返回initialized布尔,而unsafeSetInitialized()/unsafeSetUninitialized()(L688-L697)是仅供测试使用的显式置位方法。这提醒审查者:就绪标志的置位时机本身就是可审查的对象——若补丁中把就绪标志设置在异步初始化任务提交之后而非完成回调内,即命中 F-18/F-44。Cassandra 中大量"初始化完成后才能调用"的守卫(如 L3789、L4592 的if (!isInitialized()))都是这一模式的受保护面。
八、实战:如何在补丁审查中应用本分类
结合 targeted-review 技能的工作流(见 SKILL.md),本分类的落地方式如下:
- 信号匹配:拿到补丁后,先用 INDEX.md 的 11 类快速扫描信号判断哪些类目加载。若补丁触碰初始化/关停/异步/静态初始化,
lifecycle-and-ordering必然在列。 - 逐条对照:对每一处命中信号的新代码,按 F-01~F-44 的"定位提示"检查实际代码形态,而不是仅做关键字匹配——分类文档强调"
**Look for:**匹配代码形态 ≠ 缺陷成立,需由子代理读代码证实或证伪"。 - 多轮独立采样:SKILL.md 要求 3-5 轮独立迭代选择类目与条目,多轮命中的条目标记为高优先级;单轮命中的标记为推测性。
- 按审查焦点分组:将选中的条目按函数 / 文件 / 特性分组(每焦点 5-15 项),交给独立子代理核查,最后按 report-format.md 合并报告。
- 三要素校验:每个存活的发现必须通过"代码构造真实存在于 diff(而非仅凭缺失推断)→ 在可见上下文中成立 → 可行动(读者知道改什么)"三点检查。
九、附:F-01~F-44 速查总表
| 编号 | 缺陷模式 | 定位提示(Look for) |
|---|---|---|
| F-01 | 状态报告先于监听器注册(丢失更新窗口) | getState()后跟addListener() |
| F-02 | 异步操作开始后才注册监听器 | start()/submit()先于addEventListener() |
| F-03 | 管理接口在长初始化末尾才注册 | 端点/指标注册在多个重量级 init 步骤之后 |
| F-04 | 异步重建可见性窗口 | setReady(true)紧跟异步重建提交 |
| F-05 | 启动轮询无截止时间 | while (!ready) { sleep }无 deadline/次数上限 |
| F-06 | 消费者先于消息源拆除 | 关停块中 consumer 先停、通道后停 |
| F-07 | 后台线程初始化失败未通知派生线程 | submit后join()无异常通道 |
| F-08 | 后台线程先于所有者构造完成启动 | 构造函数体内字段赋值前start() |
| F-09 | 活性/身份在可服务前宣告 | 健康注册早于 bind/数据加载 |
| F-10 | 关停期间存活探针仍应答 | 心跳处理器不检查 isShuttingDown |
| F-11 | 停止顺序留下假活/假死窗口 | gossip.stop()先于clientTransport.close() |
| F-12 | 异步清理未等待即进入下一操作 | closeAsync()后立即重建同一标识符 |
| F-13 | 容量计数器在资源释放前递减 | slots.release()先于resource.close() |
| F-14 | 排空只等队列、不等生产者 | queue.awaitEmpty()无 producer join |
| F-15 | 静态初始化器在配置前求值 | static final X = Service.get*() |
| F-16 | 静态初始化器调度后台任务 | static {}中scheduleAtFixedRate() |
| F-17 | 初始化完成前生命周期方法被调用 | init()就绪标志在run()内 |
| F-18 | 两阶段初始化就绪标志过早可见 | ready=true在submit(initTask)后 |
| F-19 | 一次性调度任务从不重排自身 | 本应scheduleAtFixedRate却用schedule |
| F-20 | 周期任务以返回值而非时间门控重排 | if (worked) scheduleNext() |
| F-21 | 清理回调先于资源提交注册 | 构造函数中onClose()先于commit() |
| F-22 | 先提交执行器、后注册资源 | submit(task)后跟tracker.put(...) |
| F-23 | 静态初始化器循环类加载死锁 | static { initialize(); }可抛异常 |
| F-24 | 构造函数把this交给外部观察者 | 构造函数中registry.register(this) |
| F-25 | 迁移先加新条目再删旧条目 | add(new); remove(old); |
| F-26 | 守卫反转跳过 bootstrap/数据传输 | 单一布尔门控joinRing()/bootstrap() |
| F-27 | 异步写/初始化未等待即继续 | 被丢弃的 Future/CompletableFuture |
| F-28 | 初始化依赖子类构造前调用的虚方法 | 超类构造函数调用可覆写方法 |
| F-29 | 依赖字段声明在依赖源之前 | 静态字段引用下方声明的静态字段 |
| F-30 | Setter 触发读取未赋值字段的副作用 | 构造函数中 setter 触发通知/重算 |
| F-31 | 终止通知来自可重入状态机 | 状态转换处理器中 notify/event-fire |
| F-32 | 组件依赖晚于依赖它的组件初始化 | bootstrap 中 A 依赖 B 但 B 后启动 |
| F-33 | 关停序列引用未初始化字段 | close()中未守卫的字段访问 |
| F-34 | 固定时长 sleep 代替收敛等待 | 启动路径Thread.sleep(N)后读状态 |
| F-35 | 写屏障前取样快照 | currentPos()先于barrier()/发布 |
| F-36 | 首次观测不报告活性到达 | 首次路径跳过reportArrival() |
| F-37 | 首响应即移除共享监听器 | 单响应回调中tracker.remove(id) |
| F-38 | 终止标志与队列清空分步执行 | stopped=true与queue.clear()无临界区 |
| F-39 | 有界执行器自提交死锁 | 执行器任务内向同一执行器 submit |
| F-40 | 回调内阻塞等待唯一完成线程 | 回调中future.get()/await() |
| F-41 | 订阅状态被非预期线程变更 | 公开 API 直接改状态机字段 |
| F-42 | 就绪检查使用陈旧代理信号 | 用队列大小等间接信号判就绪 |
| F-43 | 后台调度先于必需状态建立 | scheduleOnce(initTask, delay)赌前置完成 |
| F-44 | 应用在异步设置完成前报告就绪 | ready.complete()在submitAsync(setup)后 |
十、使用边界与提示
- 分类文档是项目无关的通用缺陷形态(源自 Cassandra、Kafka、Iceberg 等分布式系统项目的真实 bug 修复提炼),见 SKILL.md 的说明:"它们描述的是泛化的代码级形态,而非特定项目问题。" 因此每条发现都必须回到具体补丁的真实代码去验证,模式匹配只是起点。
- 同一代码形态可能同时命中多个分类(如
concurrency-and-locking与state-and-resource-cleanup);分类的选择是概率性判断,多轮独立采样能显著降低漏检。 - 本分类的 44 条发现中,"等待缺失"(F-05/F-12/F-14/F-27)、"注册/订阅时序"(F-01/F-02/F-21/F-22)与"关停顺序"(F-06/F-11/F-13/F-38)三族是高发区,可作为优先检查顺序。
【免费下载链接】cassandraOpen source transactional distributed database. Linear scalability and proven fault-tolerance on commodity hardware or cloud infrastructure without compromising performance.项目地址: https://gitcode.com/GitHub_Trending/cassa/cassandra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考