概述
Lincheck 是一个用于在 JVM 平台上测试并发代码的框架. 在运行测试时, Lincheck 会探索程序中潜在的 线程交叉执行情况, 并报告那些导致错误行为的部分.
在 Lincheck 中编写并发测试, 只需要列出每个线程的操作和预期的断言. Lincheck 会处理其余的工作:
class CounterTest {
@Test // 声明测试函数
fun test() = Lincheck.runConcurrentTest {
var counter = 0
// 并发的递增 counter
val t1 = thread { counter++ }
val t2 = thread { counter++ }
// 等待线程结束
t1.join()
t2.join()
// 检查两次递增操作是否都已生效
assertEquals(2, counter)
}
}
如果测试失败, Lincheck 会提供导致错误的线程交叉执行(Interleaving)和线程切换点(Switch Point):
| ------------------------------------------------------------------------------- |
| Main Thread | Thread 1 | Thread 2 |
| ------------------------------------------------------------------------------- |
| thread(block = Lambda#2): Thread#1 | | |
| thread(block = Lambda#3): Thread#2 | | |
| switch (reason: waiting for Thread 1 to finish) | | |
| | | run() |
| | | counter ➜ 0 |
| | | switch |
| | run() | |
| | counter ➜ 0 | |
| | counter = 1 | |
| | | counter = 1 |
| Thread#1.join() | | |
| Thread#2.join() | | |
| counter.element ➜ 1 | | |
| assertEquals(2, 1): threw AssertionFailedError | | |
| ------------------------------------------------------------------------------- |
Lincheck 的工作原理
每次 JVM 运行并发代码时, 各线程间操作的执行顺序可能会发生变化. 例如, 一个操作可能会被另一个线程中的操作打断. 这本身并不是错误, 但如果代码存在并发 bug, 则可能导致错误.

Lincheck 实现了两种测试策略, 用于查找导致错误行为的执行调度:
模型检查(Model Checking). Lincheck 向程序中插入明确的的线程切换指令, 控制调度. 这些指令被放置在同步点或共享内存访问处. 模型检查使 Lincheck 能够生成导致错误的精确的执行追踪.
压力测试(Stress Testing). 由操作系统控制调度. Lincheck 对每个场景多次执行, 以增加发现错误的机会.
探索 Lincheck 的功能
阅读 Lincheck 入门 章节, 逐步学习 Lincheck 的功能特性.
阅读 测试策略 章节, 学习如何使用声明式方案测试并发数据结构.
了解更多
2026/08/02