6

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

class Foo {
 boolean b = false;

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

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

5 回答 5

10

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

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

即它可能会或可能不会起作用,你不能说它已经起作用了,它会继续起作用。


因为JIT 不能也不会b优化volatile

while (b) Thread.sleep(N);

成为

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

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

于 2012-10-01T14:19:34.860 回答
7

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

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

您需要synchronize方法(或)使用synchronize锁定this对象的块。

于 2012-10-01T14:17:04.143 回答
5

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

于 2012-10-01T14:20:41.200 回答
3

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

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

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

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

于 2012-10-01T15:10:44.640 回答
0

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

于 2012-10-01T14:19:01.677 回答