2

スレッド - GameThread - が永遠にループし、すべてのスプライトを更新し、レンダリングし、しばらくスリープしてからすべてをやり直すゲームを書いています。キーの押下などを処理するカスタムメイドのイベントハンドラーもあります。

ほとんどの場合、これで問題なく動作します。ただし、GameThread のレンダリング中にイベントがスローされると問題が発生します。まれに、イベントを処理するハンドラーが、レンダリングする必要があるものを同時に変更し、GameThread レンダリングの結果に影響を与える場合があります。

これを回避するには、イベント ハンドラーで GameThread をすぐに一時停止し、イベントを処理してから、GameThread を再開する必要があります。

  1. suspend()/メソッドはresume()私のニーズに合っていますが、廃止されました。ただ、私の場合はデッドロックの可能性が少ないので、そのまま使っても大丈夫でしょうか?

  2. いいえの場合、オーバーヘッドが大きくない他の代替手段はありますか?

一時停止するスレッドにフラグを設定して、スレッドの一時停止を要求するという提案を見たことがあります。ただし、私の場合、ループの反復中に GameThread ループに時間がかかる可能性があるため、実行可能なオプションとは思えません。ループが完了するまでフラグをチェックすることはできず、それまでには手遅れです。

すぐに一時停止する必要があります。そうしないと、ユーザーがイベント処理の遅延に気付くことになります。

4

3 に答える 3

1

リソースへのアクセスを同期する場合は、ReentrantLock を使用します。

ReentrantLock sync = new ReentrantLock();

共有データにアクセスする各ランナブルにそのロックを渡す必要があります。

次に、問題のリソースにアクセスしている各場所で、その共有ロック オブジェクトを使用し、ロック (つまり、クリティカル セクション) を取得して解放します。

sync.lock();

try {
  // critical section code here
}
finally {
  sync.unlock();
}

これは、Java での標準的な並行プログラミングです。"lock" はブロッキング メソッドであるため、代わりに "tryLock" を使用することをお勧めします。これにより、ロックを試行して取得できますが、実際にロックを取得したかどうかに関するブール値が返されます。

 if (sync.tryLock()) {
   try {
     //critical section
   }
   finally {
     sync.unlock();
   }
 }

ロックの取得をあきらめて偽の値を返す前に、一定時間待機する「tryLock」のバージョンがあります。

于 2012-03-31T03:14:41.403 に答える
1

通常、いくつかのスレッド同期を行います。

これにより、ゲームのレンダリング スレッドでレンダリングするか、イベントに基づいて変更を行うという 2 つの作業のうちの 1 つを行うことができます。

あなたが直面している問題は、レンダリング コードが実際にスムーズなエクスペリエンスを得るには時間がかかりすぎることです (つまり、何かをレンダリングしている間に処理のために多くのイベントが積み重なる可能性があります)。その場合、レンダリングを独立したピースから作成して、すばやく終了して同期できるようにする必要があります。

コードがなければ具体的なアドバイスはできませんが、一般的には次のようになります。

List<Shape> shapesToRender;
Object lockObject = new Object(); // Note this must be somehow shared between two threads

// Your rendering thread method
public void renderForever() {
  while(true) {
    for(Shape shape: shapesToRender) {
      synchronized(lockObject) {
        render(shape);
      }
    }
  }
}

// One of your event handlers
public void handleEvent(Event event) {
  synchronized(lockObject) {
    // Process event somehow, e.g. change the color of some of the shapes
    event.getShape().setColor(Color.RED);
  }
}

上記の場合、次のいずれかです。

  • 1 つの形状をレンダリングします (そして、すべてのイベント ハンドラーはそれが終了するのを待機します)、または
  • イベント ハンドラーの一部が何かを実行します (レンダリング スレッドはそれが完了するのを待機します)。

この Java トレイルをさらに詳しく見てください。

ロックオブジェクトを使用するなど、他の解決策があるため:

または同時コレクション:

問題によっては、より簡単で、最も重要なこととして、標準的な方法で何かを実行できる非常によくテストされたソリューションである可能性があるため、カスタムスレッドコードを展開するときに陥る可能性のあるすべての落とし穴を回避できます。

お役に立てれば。

于 2012-03-31T03:16:34.580 に答える
0

suspend() / resume() メソッドは私のニーズに合っていますが、廃止されました。ただ、私の場合はデッドロックの可能性が少ないので、そのまま使っても大丈夫でしょうか?

明らかに、デッドロックの可能性がゼロであれば安全です。しかし、デッドロックを発生させる予期しない方法がたくさんあります。たとえば、クラスの初期化中にスレッドを一時停止すると、そのクラスの静的フィールドを参照しようとする他のスレッドがデッドロックする可能性があります。(これは、JVM の指定された動作の結果です。フードの下で行われるロック/同期が指定されていない場所が他にもあります。十分に公平です。使用を検討している場合を除き、そうである必要はありません ...これらの廃止されたメソッド)。

ですから、本当に安全かどうかを判断(証明)するのは本当に難しいのが実情です。そして、これを判断できない場合、それは潜在的に危険なことです。そのため、メソッドは非推奨です。

(厳密にはデッドロックではありません。デッドロックとは、スレッドが先に進めない状態です。この場合、一時停止したスレッドを再開できれば、他のスレッドは続行できます。)

于 2012-03-31T03:34:41.220 に答える