我已经将以下课程作为我所参与的项目的一部分(重写/重命名以简化示例):
public class Temp {
private boolean bool = false;
// edit 1: calibrate called by other threads in the program
public void calibrate() {
bool = true;
}
public Temp() {
thread.start();
}
private final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
if(bool) {
// do some different work
bool = false;
}
else {
// do regular work
}
}
}
});
}
代码本质上提供了校准方法,可以暂时改变线程正在进行的工作。但是,这使用了一个原始的布尔值,当两个线程都写入变量时,它会让我感到惊讶。
这不需要某种同步吗?我认为它应该但它能以某种方式正常工作。如果它不需要同步,为什么?
编辑2:这不是我的代码,其他人也是这样 - 我正在修理它! :)
答案 0 :(得分:4)
它现在可能正在运作,但它没有做对。
原始数据类型不是线程安全的,没有什么可以证明它是正确的。这就是JDK为您提供Atomic
类作为原始数据类型的线程安全包装器的原因。我会毫无疑问地将bool
替换为AtomicBoolean
,否则代码就会失败。
查看此blog,显示与多线程环境中使用的基元不一致的测试结果。
答案 1 :(得分:3)
如果不了解更多有关正在发生的事情的背景,很难说代码是否正确。
如果布尔值为真,第一个线程进入第一个块,并且在其中间另一个线程将其更改为false,是否可以?您是否希望允许两个线程进入第一个块,即使其中一个线程要将其更改为false而另一个仍在true
块中运行?在这种情况下,你需要在块本身周围有更多的同步结构,而不仅仅是一个简单的布尔检查。
关于基元的同步,你应该做的一件事就是将其声明为private volatile boolean bool = false;
这样可以确保每个线程都不会保留其值可能过时的变量的本地缓存副本。
如果您想要对变量本身进行线程安全更新,您还可以选择使用AtomicBoolean
,但我怀疑这是您的线程安全问题中最少的。
答案 2 :(得分:1)
安全或活力失败很少发生,但是当它发生时,它总是在生产中负载很重的时候。
最近我试图尝试一些竞争条件来表示正确引入同步块的必要性。但大多数时候,我必须非常谨慎地设计它以使其重新出现。
您的演示中有几个问题需要修复同步。
正如@ St.Antario所指出的那样,当构建函数中的构建函数时, 更好 <作为父级()),当子类仍未完全初始化时,线程将访问子类中重写的某些方法可能很危险。
答案 3 :(得分:0)
通过你的评论
其他线程调用calibrate()方法
可能存在由并发问题引起的语义问题。
当内部线程将布尔变量重置为false并且同时或在关闭时段内,外部线程在bool
语句结束之前将if
变量更新为true时会发生什么。您希望执行regular work
,但您将执行some different work
,因为外部线程会在重新检查true
条件之前将值更改回while
。