Operasi sensitif di lab saya hari ini benar-benar salah. Aktuator pada mikroskop elektron melewati batasnya, dan setelah serangkaian peristiwa saya kehilangan $ 12 juta peralatan. Saya mempersempit lebih dari 40 ribu baris dalam modul yang salah untuk ini:
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);
}
}
Beberapa sampel dari output yang saya dapatkan:
$ 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
Karena tidak ada aritmatika floating point di sini, dan kita semua tahu bilangan bulat yang ditandatangani berperilaku baik pada overflow di Jawa, saya pikir tidak ada yang salah dengan kode ini. Namun, meskipun output menunjukkan bahwa program tidak mencapai kondisi keluar, ia mencapai kondisi keluar (keduanya tercapai dan tidak tercapai?). Mengapa?
Saya perhatikan ini tidak terjadi di beberapa lingkungan. Saya menggunakan OpenJDK 6 di Linux 64-bit.
final
kualifikasi (yang tidak berpengaruh pada bytecode yang dihasilkan) ke bidang x
dan y
"memecahkan" bug. Meskipun tidak memengaruhi bytecode, bidang ditandai dengan itu, yang membuat saya berpikir ini adalah efek samping dari optimasi JVM.
Point
p
dikonstruksi yang memuaskan p.x+1 == p.y
, lalu a referensi dilewatkan ke tempat pemungutan suara. Akhirnya utas pemungutan suara memutuskan untuk keluar karena menganggap kondisinya tidak terpenuhi untuk salah satu yang Point
diterimanya, tetapi kemudian output konsol menunjukkan bahwa ia seharusnya sudah puas. Kurangnya di volatile
sini berarti bahwa tempat pemungutan suara mungkin macet, tapi itu jelas bukan masalah di sini.
synchronized
membuat bug tidak terjadi? Itu karena saya harus menulis kode secara acak sampai saya menemukan kode yang akan mereproduksi perilaku ini secara deterministik.