การปฏิบัติที่ละเอียดอ่อนในห้องปฏิบัติการของฉันในวันนี้ผิดไปอย่างสิ้นเชิง แอคชูเอเตอร์ในกล้องจุลทรรศน์อิเล็กตรอนวิ่งข้ามขอบเขตของมันและหลังจากเหตุการณ์หลายอย่างฉันก็สูญเสียอุปกรณ์มูลค่า 12 ล้านเหรียญ ฉันแคบลงกว่า 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 ฉันคิดว่าไม่มีอะไรผิดปกติกับรหัสนี้ อย่างไรก็ตามแม้จะมีเอาต์พุตที่ระบุว่าโปรแกรมไม่สามารถเข้าถึงเงื่อนไขการออกได้ แต่ก็มาถึงเงื่อนไขการออก (มันมาถึงแล้วและไม่ถึง?) ทำไม?
ฉันสังเกตว่าสิ่งนี้ไม่ได้เกิดขึ้นในบางสภาพแวดล้อม ฉันใช้OpenJDK 6 บน Linux 64 บิต
final
(ซึ่งไม่มีผลกับรหัสไบต์ที่ผลิต) ลงในฟิลด์x
และy
"แก้ไข" ข้อบกพร่อง แม้ว่ามันจะไม่ส่งผลกระทบต่อ bytecode แต่ฟิลด์นั้นถูกตั้งค่าสถานะไว้ซึ่งทำให้ฉันคิดว่านี่เป็นผลข้างเคียงของการเพิ่มประสิทธิภาพ JVM
Point
p
ถูกสร้างขึ้นซึ่งเป็นที่น่าพอใจp.x+1 == p.y
จากนั้นการอ้างอิงจะถูกส่งผ่านไปยังเธรดการสำรวจ ในที่สุดเธรดการโพลตัดสินใจที่จะออกเนื่องจากมันคิดว่าเงื่อนไขไม่เป็นไปตามที่ได้รับอย่างใดอย่างหนึ่งPoint
แต่จากนั้นเอาต์พุตคอนโซลจะแสดงว่ามันควรจะได้รับความพึงพอใจ การขาดvolatile
ที่นี่เพียงแค่หมายความว่าการสำรวจความคิดเห็นอาจติด แต่ที่ชัดเจนไม่ได้เป็นปัญหาที่นี่
synchronized
ทำให้ข้อผิดพลาดไม่เกิดขึ้นได้อย่างไร นั่นเป็นเพราะฉันต้องเขียนโค้ดแบบสุ่มจนกว่าฉันจะพบรหัสที่จะทำซ้ำพฤติกรรมนี้อย่างแน่นอน