マルチスレッド:それらを使用しているオブジェクトがnullに設定されています
-
21-08-2019 - |
質問
私は、レンダリングスレッドを持っている小さなアプリを持っています。すべてのこのスレッドではありません彼らの現在の場所で私のオブジェクトを描画されます。
私のようないくつかのコードを持っています:
public void render()
{
// ... rendering various objects
if (mouseBall != null) mouseBall.draw()
}
それから私はまた、ユーザーがマウスをクリックしたときに新しいボールにmouseBallを作成し、設定し、いくつかのマウスハンドラを持っています。ユーザーはその後、周りのマウスをドラッグすることができ、マウスがどこに行くボールが続きます。ユーザーがボールを離すと、私はmouseBall = nullを設定し、別のマウスイベントを持っています。
問題は、私のレンダリングループがランダムな時間に(mouseBall!= null)の条件がtrueを返しますが、その割りに二そのポイントの後にユーザーがマウスを移動して、I'LLできるようになることを十分に速く実行されている、ありますnullオブジェクト上)(.drawしようとするためのnullポインタ例外を取得します。
このような問題に対する解決策は何ですか?
解決
問題は、あなたがそれをmouseBall
と別のそれに関数を呼び出すことではないかどうかを確認するために1回、2回null
にアクセスしているという事実にあります。あなたは、このように一時的に使用することで、この問題を回避することができます:
public void render()
{
// ... rendering various objects
tmpBall = mouseBall;
if (tmpBall != null) tmpBall.draw();
}
他のヒント
あなたは場合を同期させ、それらが1つの原子のシーケンスとして実行されることが保証されるように、文を描画する必要があります。 Javaでは、これがそうのように行われます。
public void render()
{
// ... rendering various objects
synchronized(this) {
if (mouseBall != null) mouseBall .draw();
}
}
私はあなたがすでに他の回答を受け入れてきた知っているが、第三の選択肢は、は、java.util.concurrent.atomicパッケージのAtomicReferenceクラスを使用することです。これは、検索、更新を提供し、あなたが任意のサポートコードを必要とせずにアトミック行動操作を比較します。だからあなたの例でます:
public void render()
{
AtomicReference<MouseBallClass> mouseBall = ...;
// ... rendering various objects
MouseBall tmpBall = mouseBall.get();
if (tmpBall != null) tmpBall.draw();
}
これはグレッグのソリューションと非常によく似ていますし、概念的には、両方の舞台裏という点で類似していた値の鮮度を確保するためのボラティリティを使用して、値を使用する前に、条件を適用するために一時的なコピーを取ります。
したがってここで使用される正確な例はAtomicReferencesの力を示すこと良くありません。コードの様々な初期スタイルのブロックのための便利なイディオム - あなたの他のスレッドがすでにヌルだった場合にのみ、vairable mouseballを更新することを代わりに考えてみましょう。あなたがそれを設定しようとしたとき、この場合、それは通常、あなたがチェックし、ボールがnullだった場合、それはがまだがヌルになることを保証するために、同期を使用することが不可欠だろう(そうでない場合、あなたは戻っていますあなたの元の問題のレルムで)。しかし、AtomicReferenceであなたは、単に言うことができます:
mouseBall.compareAndSet(null, possibleNewBall);
これはアトミック操作ですので、一つのスレッドがヌルとしての価値を「見る」場合、他のスレッドがそれを読む機会を得る前に、それはまたpossibleNewBallリファレンスに設定されます。
ので、 あなたは無条件に何かを設定するが、古い値とクリーンアップのいくつかの種類を実行する必要がある場合は、アトミック参照を持つもう一つの素敵なイディオムです。その場合にあなたが言うことができます:
MouseBall oldBall = mouseBall.getAndSet(newMouseBall);
// Cleanup code using oldBall
AtomicIntegersは、これらの利点と多くを持っています。それは関係なく、スレッドのインターリーブの、異なった値を返すには、各コールを保証できるようgetAndIncrement()メソッドは、グローバルに共有カウンターのための素晴らしいです。大騒ぎの最小とスレッドセーフます。