概述
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 的功能特性.
学习如何在 Lincheck 中 使用声明式方案测试并发数据结构.
了解更多
2026/09/29