-
03-07-2019 - |
質問
このように設定されたクラスに出くわしました:
public class MyClass {
private static boolean started = false;
private MyClass(){
}
public static void doSomething(){
if(started){
return;
}
started = true;
//code below that is only supposed to run
//run if not started
}
}
静的メソッドに関する私の理解は、定数でない限り、クラス変数を使用するべきではなく、変更しないことです。代わりに、パラメーターを使用する必要があります。私の質問は、MyClass.doSomething()を実行して複数回呼び出されたときにこれが壊れない理由です。私には、それは機能するべきではないが、機能するように思えます。 ifステートメントは1回だけ渡されます。
だから誰もこれが壊れない理由を説明できますか?
解決
メソッド doSomething()
と変数 started
は両方とも静的であるため、変数のコピーは1つしかなく、 doSomething()からアクセスできます。
。 doSomething()
が初めて呼び出されたとき、 started
はfalseであるため、 started
をtrueに設定してから...なんとかします。 2回目以降に呼び出される started
はtrueなので、何もせずに戻ります。
他のヒント
静的変数の使用が機能しない理由はありません。特に良い方法とは言いませんが、うまくいくでしょう。
何が起こるべきか:
- 最初の呼び出しが行われます。クラスは初期化され、startedはfalseです。
- doSomethingが呼び出されます。 ifは失敗し、コードはそれをバイパスします。 startedはtrueに設定され、他のコードが実行されます。
- doSomethingが再び呼び出されます。 ifがパスして実行が停止します。
注意すべきことは、ここでは同期が行われないことです。したがって、doSomething()が別々のスレッドで呼び出された場合、各スレッドはfalseとして開始され、ifステートメントをバイパスして作業を実行できます。競合状態。
指定されたコードはスレッドセーフではありません。このコードをスレッドセーフにする簡単な方法は、
public class MyClass {
private static AtomicBoolean started = new AtomicBoolean(false);
private MyClass(){
}
public static void doSomething(){
boolean oldValue = started.getAndSet(true);
if (oldValue)
return;
}
//code below that is only supposed to run
//run if not started
}
}
AtomicBoolean getAndSetが同期されるため、これはスレッドセーフである必要があります。
確かに、スレッドを使用しない場合、これは問題ではありません(Webアプリケーションは、気付かないうちにさまざまなリクエストを処理する非常に多くのスレッドを使用できることに注意してください)。
特に良いコードではありません-一般に、設計では状態が変化するオブジェクトインスタンスを使用する必要がありますが、違法ではありません。
静的メソッドに関する私の理解は、定数でない限り、クラス変数を使用するべきではなく、変更しないことです。
デザインガイドラインから言語機能への外挿を行っているようです。言語で実際に許可されているものについて、オンラインで利用できる多くのJavaチュートリアルの1つを読んでください。静的メソッドでは、最終ではない静的フィールドを自由に使用できますが、オブジェクト指向コードではなく手続き型コードになります。
代わりに、パラメータを使用する必要があります。
started
パラメータがどのように使用されるかわかりにくい-呼び出し元がプロセスが開始されたことを知っていた場合、なぜメソッドを呼び出すのか?
静的メソッド内では、同じクラス内の静的メンバーを呼び出したりアクセスしたりできます。
複数のスレッドのシナリオを無視して、 doSomethingの最初の呼び出しは、ブール型の静的変数をtrueにします。したがって、2番目の呼び出しは、メソッドを単に終了するifブロックのコードを実行します。
静的メソッドは静的クラス変数と通信しているため、問題ありません。 これは、クラスの名前空間にあるグローバルコードとグローバル変数と考えることができます。
非静的メンバー変数にアクセスしようとした場合:
private int foo = 0;
静的メソッド内から、コンパイラーは文句を言うでしょう。
started is false - initial state.
MyClass.doSomething() - statered is now true
MyClass.doSomething() - started is STILL true
MyClass foo = new MyClass();
foo.started -> it's STILL true, because it's static
foo.doSomething() - not sure you can do this in Java, but if you can, it's be STILL TRUE!
現在、上記のコードにはスレッドセーフに関する問題がありますが、それ以外は設計どおりに機能しているようです。
「静的変数はクラスレベル変数であり、すべての非静的変数はインスタンス変数です」という経験則を覚えておいてください。そうすれば、混乱はまったくありません!
i.e。 静的変数の場合、変数へのコードで行われたすべての参照は、同じメモリ位置を指します。また、非静的変数の場合、そのクラスの新しいインスタンスが作成されるたびに新しいメモリ割り当てが行われます(したがって、変数へのコードで行われたすべての参照は、クラスインスタンスの呼び出しに割り当てられた異なるメモリ位置を指します)。
上記のコードは完全に機能します(マルチスレッド環境で実行しない限り)。なぜ壊れるはずだと思いますか?
静的メソッドについての私の理解は、定数でない限り、クラス変数を使用するべきではなく、変更しないことです
静的メンバーのみにアクセスできると思います。一定である必要はありません!
私の質問は、MyClass.doSomething()を実行して複数回呼び出されたときにこれが壊れない理由です。私には、それは機能するべきではないが、機能するように思えます。 ifステートメントは1回だけ渡されます
既存のロジックごと。最初の呼び出しのみが // code to be run
part