Một hoạt động nhạy cảm trong phòng thí nghiệm của tôi hôm nay đã hoàn toàn sai. Một thiết bị truyền động trên kính hiển vi điện tử đã đi qua ranh giới của nó, và sau một chuỗi sự kiện tôi đã mất 12 triệu đô la thiết bị. Tôi đã thu hẹp hơn 40K dòng trong mô-đun bị lỗi này:
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);
}
}
Một số mẫu đầu ra tôi nhận được:
$ 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
Vì không có bất kỳ số học dấu phẩy động nào ở đây và tất cả chúng ta đều biết các số nguyên đã ký hoạt động tốt trên tràn trong Java, tôi nghĩ rằng không có gì sai với mã này. Tuy nhiên, mặc dù đầu ra chỉ ra rằng chương trình không đạt được điều kiện thoát, nhưng nó đã đạt đến điều kiện thoát (cả hai đều đạt và không đạt?). Tại sao?
Tôi đã nhận thấy điều này không xảy ra trong một số môi trường. Tôi đang dùng OpenJDK 6 trên Linux 64 bit.
final
vòng loại (không ảnh hưởng đến mã byte được sản xuất) vào các trường x
và y
"giải quyết" lỗi. Mặc dù nó không ảnh hưởng đến mã byte, nhưng các trường được gắn cờ với nó, điều này khiến tôi nghĩ rằng đây là tác dụng phụ của tối ưu hóa JVM.
Point
p
được xây dựng thỏa mãn p.x+1 == p.y
, sau đó một tham chiếu được chuyển đến chuỗi bỏ phiếu. Cuối cùng, chuỗi bỏ phiếu quyết định thoát vì nó nghĩ rằng điều kiện không được thỏa mãn đối với một trong những Point
điều nó nhận được, nhưng sau đó đầu ra giao diện điều khiển cho thấy rằng nó nên được thỏa mãn. Việc thiếu volatile
ở đây chỉ đơn giản có nghĩa là chuỗi bỏ phiếu có thể bị kẹt, nhưng rõ ràng đó không phải là vấn đề ở đây.
synchronized
khiến lỗi không xảy ra? Đó là bởi vì tôi phải viết ngẫu nhiên mã cho đến khi tôi tìm thấy một mã sẽ tái tạo hành vi này một cách xác định.