Bugün laboratuvarımdaki hassas bir operasyon tamamen yanlış gitti. Bir elektron mikroskobu üzerindeki bir aktüatör sınırlarını aştı ve bir olay zincirinden sonra 12 milyon dolarlık ekipman kaybettim. Hatalı modülde 40K hattı üzerinde daralttım:
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);
}
}
Bazı örnekler çıktı alıyorum:
$ 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
Burada herhangi bir kayan nokta aritmetiği olmadığından ve hepimiz işaretli tam sayıların Java'da taşma üzerinde iyi davrandığını bildiğimiz için, bu kodda yanlış bir şey olmadığını düşünürdüm. Ancak, programın çıkış durumuna ulaşmadığını gösteren çıktıya rağmen, çıkış durumuna ulaştı (hem ulaşıldı hem de ulaşılmadı?). Neden?
Bunun bazı ortamlarda olmadığını fark ettim. 64 bit Linux üzerinde OpenJDK 6 kullanıyorum.
final
alanlara (üretilen bayt üzerinde bir etkisi yoktur) eleme x
ve y
"çözer" böcek. Bayt kodunu etkilemese de, alanlar onunla işaretlenir, bu da bunun bir JVM optimizasyonunun bir yan etkisi olduğunu düşündürüyor.
Point
p
tatmin edici bir şekilde inşa edilir p.x+1 == p.y
, daha sonra yoklama ipliğine bir referans geçirilir. Sonunda yoklama ipliği çıkmaya karar verir, çünkü koşulun Point
aldığı slerden biri için tatmin olmadığını düşünür , ancak konsol çıktısı bunun yerine getirilmesi gerektiğini gösterir. volatile
Burada eksiklik , yoklama iş parçacığının sıkışabileceği anlamına gelir, ancak bu açıkça sorun değildir.
synchronized
hatayı nasıl gerçekleştirdiğini fark ettiniz mi? Çünkü bu davranışı deterministik olarak yeniden oluşturacak bir kod bulana kadar rastgele kod yazmak zorunda kaldım.