今天,我实验室中的一个敏感操作完全出错。电子显微镜上的执行器越过边界,经过一连串的事件,我损失了1200万美元的设备。我将有故障的模块中的超过40K行缩小为:
import java.util.*;
class A {
static Point currentPos = new Point(1,2);
static class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
new Thread() {
void f(Point p) {
synchronized(this) {}
if (p.x+1 != p.y) {
System.out.println(p.x+" "+p.y);
System.exit(1);
}
}
@Override
public void run() {
while (currentPos == null);
while (true)
f(currentPos);
}
}.start();
while (true)
currentPos = new Point(currentPos.x+1, currentPos.y+1);
}
}
我得到的一些输出示例:
$ java A
145281 145282
$ java A
141373 141374
$ java A
49251 49252
$ java A
47007 47008
$ java A
47427 47428
$ java A
154800 154801
$ java A
34822 34823
$ java A
127271 127272
$ java A
63650 63651
由于这里没有任何浮点算法,而且我们都知道有符号整数在Java中的溢出情况下表现良好,因此我认为这段代码没有错。但是,尽管输出表明程序未达到退出条件,但程序仍达到了退出条件(是否达到
和 未达到?)。为什么?
我注意到这在某些环境中不会发生。我在64位Linux 上使用OpenJDK
6。
显然,在读取currentPos之前不会发生写入,但是我看不出这可能是个问题。
currentPos = new Point(currentPos.x+1, currentPos.y+1);
做一些事情,包括将默认值写入x
和y
(0),然后将其初始值写入构造函数。由于没有安全地发布您的对象,因此编译器/
JVM可以自由地重新排序这4个写操作。
因此,从读取线程的角度来看,x
以新值但y
默认值为0进行读取是合法的执行。当您到达该println
语句时(顺便说一下,该语句已同步,因此确实会影响读取操作),这些变量具有其初始值,程序将打印期望值。
标记currentPos
为volatile
可以确保安全发布,因为您的对象实际上是不可变的-
如果在实际使用情况下,对象在构造后发生了突变,则volatile
保证不够,您可能会再次看到不一致的对象。
或者,您可以使Point
不可变,即使不使用也可以确保安全发布volatile
。要实现不变性,您只需要标记x
并y
最后确定即可。
附带说明一下,正如已经提到的,synchronized(this) {}
JVM可以将其视为无操作(我知道您将其包括在内可以重现此行为)。
今天我实验室的一个敏感操作完全出了问题。一台电子显微镜上的一个致动器越过了它的边界,在一系列事件之后,我损失了1200万美元的设备。我将故障模块中的40K行缩小到以下范围: 我得到的一些输出示例: 因为这里没有任何浮点运算,而且我们都知道有符号整数在Java溢出时表现良好,所以我认为这段代码没有问题。然而,尽管输出表明程序没有达到退出条件,但它却达到了退出条件(既达到了又没有达到?)。为什么? 我
我有一个简单的功能,我想测试,但明显的结果是没有发生。。。 我的函数是如何工作的(实际上它确实工作,只是没有正确测试) 我将字符串传递到函数中 当我运行所示的测试时,我收到错误: 预期默认值等于hare失败 我的组件 我的测试
问题内容: 考虑以下程序: 为什么它在本地终止而不在Playground终止?我的程序终止是否依赖未定义的行为? 问题答案: 该代码不能提供太多保证。它几乎完全依赖于围绕未定义行为的实现细节。 在大多数多线程系统中,不能保证一个线程中的更改不会出现障碍。您有一个goroutine,可以在另一个处理器上运行,总共将一个值写入一个没有人保证读取的变量。 将可以很容易地重写,因为从未有一个保证该变量的任
我的老师让我这样做,但在评论区我被告知我不应该这样做。 为什么?
问题内容: 触发服务器调用以获取componentWillMount生命周期方法中的数据是一种不好的做法? 以及为什么最好使用componentDidMount。 问题答案: 更新: componentWillMount将很快被弃用。 引用@Dan Abramov 在 React的未来版本中,我们期望componentWillMount 在某些情况下 会触发多次 ,因此您应该对网络请求使用comp
自从在JDK1.0中引入Object#Finalize()之后,Java又推出了9个版本。 然而,尽管它有明显的缺点,但它仍然可用,即使在JDK10中也是如此。 这就引出了一个问题:这种方法是否有任何已知的正确用法?