Lombok 拾遗
Created|Updated|Java
|Word Count:43|Reading Time:1mins|Post Views:
sneakyThrow
1 | |
Author: magicliang
Copyright Notice: All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
Related Articles

2026-01-18
无锁队列
Java 一读一写(SPSC):Memory Barrier + Volatile 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657/** * Single-Producer Single-Consumer (SPSC) 无锁环形队列。 * * <p>原理说明: * - 仅允许一个线程调用 {@code offer()},一个线程调用 {@code poll()}。 * - 由于没有写竞争,无需 CAS;只需保证写操作对消费者可见。 * - 使用两个 volatile 索引(head/tail)建立 happens-before 关系: * 生产者写入元素 → volatile 写 tail → 消费者 volatile 读 tail → 读取元素。 * - 这本质上利用了 Java 内存模型中的“volatile 写-读”内存屏障(StoreLoad), * ...
2020-04-01
ThreadLocal 的设计模式
ThreadLocal 是 Java 并发编程中实现**线程封闭(Thread Confinement)**的核心工具。本文将从原理到实践,系统性地讲解 ThreadLocal 的设计哲学、内部机制、使用模式以及跨线程传递方案。 原理篇:ThreadLocal 的内部机制 核心设计理念:为什么不用 Map<Thread, Value>? 很多人初次设计线程本地存储时,会想到用一个全局的 Map<Thread, Value> 来存储每个线程的数据。但这种设计有致命缺陷:Thread 对象会被 Map 强引用,导致线程无法被 JVM 回收,造成严重的内存泄漏。 ThreadLocal 采用了相反的设计:让 Thread 持有 Map,而不是让 Map 持有 Thread。每个 Thread 内部都有一个 ThreadLocalMap,用于存储该线程的所有线程本地变量。这样设计的好处是: 线程销毁时,ThreadLocalMap 随之销毁,数据自动清理 ThreadLocal 对象可以被显式管理(如声明为静态变量) 线程内部的存储容器是隐式的,由线程自己管理 ...

2026-05-14
缓存系统设计全景——从原理到生产的完整指南
缓存是提升系统性能的第一利器,但也是引发故障的第一杀手。从缓存穿透、击穿、雪崩三大经典问题,到多级缓存架构、分布式锁、热点 Key 治理,缓存设计几乎贯穿后端工程师的整个职业生涯。 本文将系统性地剖析缓存系统的设计原则与生产实践,从单机进程内缓存到分布式 Redis 集群,从理论模型到可落地的代码方案,构建一套完整的缓存知识体系。 mindmap root((缓存架构)) 何时使用 读多写少 热点集中 可容忍最终一致性 缓存层次 近端缓存 Guava Caffeine EhCache 远端缓存 Redis Memcached 核心挑战 更新策略 Cache Aside Read Through Write Through Write Behind 一致性保障 故障防护 击穿防护 雪崩防...
2026-05-21
写一个 lambda 规约器
上一篇文章把 lambda 演算拆成三种表达式:变量、函数、调用。示例只做了最小的一步替换,用来说明函数应用可以变成表达式重写。 本文把这件事补成一个规约器:给定一个 lambda 表达式,持续执行 beta 规约,打印每一步轨迹,并处理替换过程中最容易出错的变量捕获问题。这个规约器仍然很小,但已经具备解释器和 AST 重写器的基本骨架。 规约器要解决什么 lambda 演算的核心计算规则是 beta 规约: 12(x -> body) argument -> body 中的自由 x 替换成 argument 例如: 12(x -> x) a -> a 更复杂一点的例子: 123(((x -> (y -> x)) a) b) -> ((y -> a) b) -> a 规约器需要完成三件事: 职责 作用 找到可规约位置 判断哪一个调用先执行 做安全替换 只替换自由变量,避免误改绑定变量 重复执行 直到表达式无法继续变化 这和解释器很接近。区别在于解释器通常维护环境和值,lambda 规约器直...
2017-11-30
Java中的幽灵类型
什么是幽灵类型 先上结论:幽灵类型(Phantom Type)顾名思义,就是幽灵般的类型,这种类型往往在运行时可以消失,因为在运行时没有任何作用,它们最大的特点就是没有任何实例(Java 的 Void 就是一个不可实例化类型的例子,常被用作幽灵类型的类型参数,如 Future<Void>)。幽灵类型是一种可以把有些运行时才能检测到的错误,在编译时检测出来的技巧。按照有些老外的观点,就是"Making Wrong Code Look Wrong"。在面向对象的编程语言之中,幽灵类型的实现,往往与状态模式较为接近,但比状态模式提供了更强的纠错功能。在 Java 5 以后的版本里,程序员可以使用泛型。通过泛型的类型参数,Java 中也拥有了幽灵类型的能力。 上面的阐述是不是很难看懂?直接进入具体的例子。假设有一个飞机控制程序,操作飞机起飞或者落地。这个程序有一个非常强的业务约束,就是必须保证飞机一开始必须出现在地上,只有在地上的飞机可以起飞,只有起飞的飞机可以落地,那么应该怎样设计程序(主要是类型关系),来保证这个约束必然成立呢? 定义状态接口 先来定义...
2026-05-21
图灵机:纸带、读写头和最小通用计算
DFA 只有有限状态。NFA 允许同时保留多个状态。PDA 在有限状态之外加了一只栈,可以处理任意深度的嵌套。图灵机再往前走一步:它把栈换成一条可以读、写、左右移动的纸带。 这个变化很小,却足以把机器能力推到通用计算。图灵机仍然只有有限个控制状态,每一步仍然按规则机械执行;不同的是,机器可以在纸带上写下中间结果,之后再移动回来读取。程序状态和可变存储被明确分开。 本文先写一台最小确定性图灵机(Deterministic Turing Machine,DTM)。示例很小:读写头从第一个字符开始,把当前位置的符号改成 1,向右移动一格,然后停机。下一篇再用同一套结构实现一个稍微有算法味的纸带程序。 图灵机比 PDA 多了什么 PDA 的栈只能操作一端。读写都发生在栈顶,历史只能以后进先出的方式取回。图灵机的纸带更自由:读写头可以向左或向右移动,机器可以反复回到某个位置修改内容。 模型 有限控制 可增长存储 读写位置 典型能力 DFA / NFA 有 无 无 正则语言 PDA 有 栈 栈顶 嵌套结构 图灵机 有 纸带 当前格,可左右移动 通用计算 这个表里...
Contents
