2

このコード:

synchronized (mList) {
    if (mList.size() != 0) {
        int s = mList.size() - 1;
        for (int i = s; i > 0; i -= OFFSET) {
            mList.get(i).doDraw(canv);
        }
        getHead().drawHead(canv);
    }
}

AIOOBEをランダムにスローします。私が読んだことから、同期はそれを防ぐはずです、それで私は何が間違っているのですか?

編集:

AIOOBE =範囲外の配列インデックスの例外コードが不完全で、必要なものに切り詰められています。しかし、あなたを幸せにするために、OFFSETは4であり、最初に少しのデータを追加するforループがあると想像してください。そして、2番目のスレッドがリストを読み取ったり変更したりします。

編集2:

リストが描画されていて、現在のゲームが終了したときに発生することに気づきました。リストが空になったときに、draw-threadがすべての要素を描画したわけではありません。リストが空になるまでリストを空にして待つようにゲームに指示する方法はありますか?

編集3:

これがマルチスレッドの問題であるかどうかわからないことに気づきました。計算と描画用とユーザー入力用の2つのスレッドしかないようです。これについては、思ったよりも少し詳しく調べる必要があります。

4

4 に答える 4

2

あなたがしていることは正しく見えます...しかしそれだけです:

  1. 同期するオブジェクトは関係ありません。リスト自体である必要はありません。
  2. 重要なのは、共有リソースにアクセスするときに、すべてのスレッドが常に同じオブジェクトで同期するかどうかです。
  3. SWING(または別のグラフィックライブラリ)へのアクセスは、AWTスレッドで行う必要があります。

あなたの編集へ:

リストが描画されていて、現在のゲームが終了したときに発生することに気づきました。リストが空になったときに、draw-threadがすべての要素を描画したわけではありません。リストが空になるまでリストを空にして待つようにゲームに指示する方法はありますか?

「...描画が完了するまでリストを空にして待つ」という意味だと思います。同じロック(つまり、あなたの場合はリスト自体)でそれを実行するコードを同期するだけです。

繰り返しますが、共有リソースへのアクセスは何らかの方法で保護する必要があります。synchronizedリストを空にしている場所ではなく、ここだけを使用しているようです。

于 2011-08-29T13:08:04.073 に答える
0

私の提案はBlockingQueueを使用することであり、このソリューションも探していると思います。どうすればいいですか?javadocの例ですでに示されています:)

 class Producer implements Runnable {
   private final BlockingQueue queue;
   Producer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while (true) { queue.put(produce()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   Object produce() { ... }
 }

 class Consumer implements Runnable {
   private final BlockingQueue queue;
   Consumer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while (true) { consume(queue.take()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   void consume(Object x) { ... }
 }

 class Setup {
   void main() {
     BlockingQueue q = new SomeQueueImplementation();
     Producer p = new Producer(q);
     Consumer c1 = new Consumer(q);
     Consumer c2 = new Consumer(q);
     new Thread(p).start();
     new Thread(c1).start();
     new Thread(c2).start();
   }
 }

あなたにとって有益なことは、あなたがあなたのを同期することを心配する必要がないということですmListBlockingQueue10の特別な方法を提供します。ドキュメントで確認できます。javadocからのいくつか:

BlockingQueueメソッドには4つの形式があり、すぐには満たすことができないが、将来のある時点で満たされる可能性のある操作を処理するさまざまな方法があります。1つは例外をスローし、もう1つは特別な値(nullまたはfalseに応じて、操作)、3番目は操作が成功するまで現在のスレッドを無期限にブロックし、4番目はあきらめる前に指定された最大時間制限のみをブロックします。

安全を期すために:私はAndroidの経験がありません。したがって、すべてのJavaパッケージがAndroidで許可されているかどうかはわかりません。しかし、少なくともそれは:-Sであるべきです、私は望みます。

于 2011-08-29T14:36:37.890 に答える
0

安全な解決策は、ゲームの開始後に1つのスレッドのみがオブジェクトを作成し、それらをリストに追加したり、リストから削除したりできるようにすることです。

私はランダムなAIOOBEのエラーに問題があり、synchornizeでそれを適切に解決できなかっただけでなく、ユーザーの応答が遅くなりました。

私の解決策は、現在安定していて高速です(以来、AIOOBEはありません)。永続変数にフラグとタッチの座標を設定することにより、UIスレッドにゲームスレッドにオブジェクトの作成または操作を通知させることです。

ゲームスレッドは1秒間に約60回ループするため、UIスレッドからメッセージを取得して何かを実行するにはこれで十分であることがわかりました。

これは非常に単純な解決策であり、うまく機能します。

于 2011-08-29T14:02:56.770 に答える
-1

リストを操作しているスレッドが2つあり、それを誤って実行しているため、インデックスが境界例外から外れています。他のスレッドがリストを変更している間、他のスレッドがリストを反復処理できないように、別のレベルで同期している必要があります。一度にスレッド上でのみ、リストで「機能する」必要があります。

私はあなたが次の状況にあると思います:

//リストにアイテムを追加するコードの一部

synchronized(mList){
    mList.add(1, drawableElem);
    ...
}

//リストを反復するコード(簡略化されたコード)

synchronized (mList) {
    if (mList.size() != 0) {
        int s = mList.size() - 1;
        for (int i = s; i > 0; i -= OFFSET) {
            mList.get(i).doDraw(canv);
        }
        getHead().drawHead(canv);
    }
}

個々に、コードの断片はうまく見えます。それらはスレッドセーフで縫い目があります。しかし、2つの個別のスレッドセーフなコードは、より高いレベルではスレッドセーフではない可能性があります。それはあなたが次のことをしただけです:

Vector v = new Vector();
if(v.length() == 0){    v.length() itself is thread safe!
  v.add("elem");        v.add() itself is also thread safe individually!
}

しかし、複合操作はそうではありません!

よろしく、ティベリウ

于 2011-08-29T13:37:59.400 に答える