[解決済み】このJavaプログラムは、明らかに終了すべきではない(しなかった)にもかかわらず、なぜ終了するのでしょうか?)
質問
今日、私の研究室で繊細な操作が完全に失敗してしまいました。電子顕微鏡のアクチュエータが境界を越えてしまい、連鎖的に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では符号付き整数がオーバーフローに対してうまく動作することが知られているので、このコードには何も問題がないと思う。しかし、プログラムが終了条件に達していないことを示す出力があるにもかかわらず、終了条件に達しています(両方達しています と は到達していないのでしょうか)。なぜでしょうか?
環境によっては起きないことに気づきました。私は OpenJDK 6、64ビットLinux上。
解決方法は?
<ブロッククオート明らかに、currentPosへの書き込みは、読み込みの前に起こることはないのですが、それがどうして問題になるのかわかりません。
currentPos = new Point(currentPos.x+1, currentPos.y+1);
は、デフォルト値を
x
と
y
(0)とし、コンストラクタでそれらの初期値を書き込みます。オブジェクトは安全に公開されないので、これら4つの書き込み操作はコンパイラ/JVMによって自由に並べ替えが可能です。
したがって、読み取り側のスレッドから見ると、以下のように読み取ることは合法的な実行です。
x
は新しい値を持つが
y
をデフォルトの値である0に変更します。に到達するまでに
println
文(ちなみにこれは同期しているので、読み込み操作に影響します)は、変数が初期値を持ち、プログラムは期待される値を表示します。
マーキング
currentPos
として
volatile
は、オブジェクトが事実上不変であるため、安全な発行を保証します。
volatile
の保証は十分ではなく、また一貫性のないオブジェクトを目にすることになるかもしれません。
別の方法として
Point
を使わなくても、安全な公開が保証されます。
volatile
. 不変性を実現するためには、単に
x
と
y
の最終的なものです。
余談ですが、すでに述べたように
synchronized(this) {}
は、JVMによってno-opとして扱われる可能性があります(あなたはこの動作を再現するためにそれを含めたと理解しています)。
関連
-
[解決済み] コレクションへの共有参照が見つかりました org.hibernate.HibernateException
-
[解決済み] 一部の入力ファイルが非推奨のAPIを使用またはオーバーライドしている
-
[解決済み] ファイルを作成せずに、ファイルが存在するかどうかをチェックする
-
[解決済み] java.io.IOException。DER長の短い読み取り
-
[解決済み] ランダムな文字列を使用するこのコードは、なぜ "hello world" と表示されるのですか?
-
[解決済み] なぜJavaにはtransientフィールドがあるのですか?
-
[解決済み] なぜJavaのVector(およびStack)クラスは時代遅れ、または非推奨とされているのですか?
-
[解決済み] Java の assert キーワードは何をするのか、そしていつ使うべきなのか?
-
[解決済み] なぜ無限ループになるのですか?
-
[解決済み】array[idx++]+="a "は、Java 8ではidxを1回増やすが、Java 9と10では2回増やすのはなぜか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Eclipse デフォルトのフォント名
-
[解決済み] Java の substring() の時間複雑性
-
[解決済み] このフォーマット(Tue Jul 13 00:00:00 CEST 2010)の日付をJavaの日付に変換する方法(文字列はalfrescoのプロパティに由来しています)
-
[解決済み] javacが「using unchecked or unsafe operations」という警告を出す原因は何ですか?
-
[解決済み] Androidのコールバックとは何ですか?重複
-
[解決済み] JOGLまたはLWJGLの既成のプロジェクト
-
[解決済み] java.util.MissingFormatArgumentException: 形式指定子 '%s' がありません。
-
[解決済み] スリーピング中のスレッドが割り込まれ、データベースへの接続が失われる
-
[解決済み] Eclipseでクラスとそれに対応するファイルの名前を変更する方法は?
-
[解決済み] x--やx++はここで何をするのですか?