我的班级线程安全吗?如果不是为什么?
class Foo {
boolean b = false;
void doSomething() throws Exception {
while (b) Thread.sleep();
}
void setB(boolean b) {
this.b = b;
}
}
答案 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不能保证永远终止。