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

时间:2012-10-01 14:15:48

标签: java

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

class Foo {
 boolean b = false;

 void doSomething() throws Exception {
    while (b) Thread.sleep();
 }

 void setB(boolean b) {
     this.b = b;
 }
}

5 个答案:

答案 0 :(得分:10)

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

BTW:这使得测试非常困难。例如如果你睡了1秒钟,你可能几乎不会看到这种行为。

即。它可能会也可能不会起作用,你不能仅仅因为它已经奏效而继续发挥作用。


由于b不是volatile,因此JIT可以优化

while (b) Thread.sleep(N);

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

所以每次都不会读取b的值。

答案 1 :(得分:7)

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

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

您需要synchronize方法(或)使用synchronize阻止this对象的阻止。

答案 2 :(得分:5)

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

答案 3 :(得分:3)

  

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

它可以追溯到“线程安全”的定义。维基百科说:

  

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

这里的关键点是正确运行。如果你看看Peter Lawrey解释的场景,你可以看到JIT编译可能导致代码在b的值从true变为false时没有注意到,并且而是循环永远。这显然是不正确的行为。因为只有在有两个线程时才会出现,这是一个线程安全问题。

答案 4 :(得分:0)

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