假设我有以下 java 类:
static class Singleton {
static Singleton i;
static Singleton getInstance() {
if (i == null) {
i = new Singleton();
}
return i;
}
}
现在,我们都知道这会起作用,但是 - 它显然不是线程安全的 - 我实际上并没有尝试修复线程安全 - 这更像是一个演示,我的其他类是相同的,但使用互斥锁和同步 - 将针对每个运行单元测试以表明一个是线程安全的,而另一个不是。如果 getInstance 不是线程安全的,单元测试可能会失败?
最佳答案
好吧,竞态条件本质上是概率性的,因此没有确定性的方法来真正生成竞态条件。任何针对您当前代码的可能方法都需要运行多次,直到达到预期的结果。不过,您可以通过制作一个模拟单例来测试以模拟特定条件可能是什么样子,从而对 i 执行松散的访问顺序。同步的经验法则是一种预防措施,胜过在代码库中损坏错误代码后尝试测试和找出问题所在。
static class Singleton {
static Singleton i;
static Singleton getInstance(int tid) {
if (i == null) {
if (tid % 2 == 0) i = new Singleton()
}
return i;
}
}
因此某些线程将写入 i,而其他线程将读取 i,就好像它们在“偶数线程 id 能够检查和初始化 i”之前到达“返回 i”一样(有点,不完全是,但它模拟了行为).在这种情况下,偶数线程之间仍然存在竞争,因为偶数线程可能在另一个读取 null 后仍然写入 i。为了改进,您需要实现线程安全以强制一个线程读取 i 并获取 null,而另一个线程将 i 设置为 new Singleton() 的情况,这是一种线程不安全的情况。但到那时你最好只解决潜在的问题(只是让 getInstance 线程安全!)
TLDR:在不安全的函数调用中可能会出现无数种竞争条件。您可以模拟代码以生成特定竞争条件的模拟(例如,仅在两个线程之间),但仅对“竞争条件”进行全面测试是不可行的
关于java - 单元测试Java中单例类的线程安全性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48772068/