我最近与我的一位同事(我非常尊重)进行了一次小型竞赛,以确定某些代码是否是线程安全的理论可能性。
让我们假设我们从第三方库中获取了一些“黑盒子”类FooUnknown
,因此我们无法访问其原始源代码。此外,它可能是内部使用一些本机方法(如果这是一个问题)。
我们可以编写这样一个单元测试,告诉我们这个类的用法(例如,它在多个线程之间共享的实例)是100%线程安全的吗?
我的结论是,不可能。对我而言,这是显而易见的:虽然可以编写一个代码,这将导致一些可能检测到的并发问题。但是没有这样的结果并不能保证根本没有并发问题。
我也相信,这个问题不是太广泛。确切地说,我们说我们有一个班级some.FooUnknown
,我们希望以下列方式使用它:
@ApplicationScoped
public class FooService {
private some.FooUnkown foo = new some.FooUnknown();
public void someStuff() {
// ...
String result = foo.doSomeStuff();
// ...
}
}
如何测试它以确保它是线程安全的,例如我们不需要将它包装到ThreadLocal<FooUnknown>
中?
答案 0 :(得分:2)
忽略所有实际原因,这也是理论上难以实现一整套并发安全测试的原因:
假设有n
个线程在同一个数据结构上运行。然后,任何线程i
在该数据结构上具有一系列S i 原子操作,其中每个序列可以具有不同的长度。现在您需要确保在理想的环境中通过这些操作跨越所有线程的每个可能的迭代序列都包含在您的测试中。即使对于相对较小的操作序列而且只有2个线程,这个数字也会快速增长。
但现在困难的部分是将这些发现转化为真正的计算机。鉴于如何实现jvms和java内存模型的自由,识别这样的原子操作本身是一项复杂的任务。然后还有由os控制的线程调度。因此,通常无法控制在数据结构上发生的实际操作序列。
答案 1 :(得分:1)
你是对的 - 作为一个黑匣子,你不可能说它的线程是否安全..即使你测试它2周并把所有东西扔到一百万个虚拟机上,也许它现在是线程安全的,但在2018年将变得线程不安全(例如通过内部检查日期是什么以及故意在2018-01-01死锁)
答案 2 :(得分:1)
这是不可能的,因为有许多方法可以产生不安全的线程。只需本机代码中的全局变量即可。