我的类线程安全吗?如果不是为什么



我的类线程安全吗?如果不是为什么?

class Foo {
 boolean b = false;
 void doSomething() throws Exception {
    while (b) Thread.sleep();
 }
 void setB(boolean b) {
     this.b = b;
 }
}

代码不是线程安全的,因为正在运行的线程可能会看到更改,直到代码被编译(稍后可能会在随机点)并且您不再看到更改。

顺便说一句:这使得测试变得非常困难,例如,如果你睡了 1 秒钟,你可能在将近三个小时内看不到这种行为。

也就是说,它可能有效,也可能无效,你不能仅仅因为它已经工作就说它将继续工作。


由于b不是volatile JIT可以并且将会优化

while (b) Thread.sleep(N);

要成为

boolean b = this.b;
if (b) while (true) Thread.sleep(N);

因此,不会每次都读取 b 的值。

不是。 setB()更新实例变量b值,但未synchronized

多个线程可能会尝试在同一时间点执行setB()方法可能会导致不可预测的结果。

您需要synchronize方法(或)使用synchronizethis对象上锁定。

看看 AtomicBoolean。这意味着任何时候只有一个线程可以访问它。

但是,它与线程安全有什么关系?有点困惑。

它可以追溯到"线程安全"的定义。 维基百科是这样说的:

"线程安全是一种适用于多线程程序上下文的计算机编程概念。如果一段代码在多个线程同时执行期间正常运行,则该代码是线程安全的。

这里的关键点是功能正确。 如果您查看 Peter Lawrey 解释的场景,您会发现 JIT 编译可能会导致代码不会注意到b的值何时从 true 更改为 false,而是永远循环。 这显然是不正确的行为。 由于这仅在有两个线程时才表现出来,因此这是一个线程安全问题。

这里有一个问题的概念是可见性,在并发Java中讨论过。 如果 doSomething() 在不同的线程上运行,JVM 不保证在 setB 中执行的操作将应用于 doSomething 看到的 b 版本。 所以你可以调用setB,doSomething不能保证永远终止。

相关内容

最新更新