3

ですから、私はこのプロジェクトを間もなく開始しますが、スレッド同期の概念を完全には理解していないのではないかと思います。実は全然わからないようですので、質問がばかげている場合は事前にお詫び申し上げます。

アイデアは単純です。動物を表す複数のスレッド(Antilope、LionなどがAnimalimplements Runnableを拡張します)と、タイルオブジェクトの2D配列があります。動物は衝突することなく移動する必要があります。一方が別のタイルが立っているタイルに移動したい場合は、動物とinteract()する必要があります。次に、もう一方が死なない場合は、動物が離れるまで待ちます。

したがって、動物が移動するときは、2つの動物が同時に1つのタイルに入ることができないように、ターゲットタイルで同期する必要があるようです。ただし、移動するときは、立っていたタイルでnotify()を呼び出す必要があるようです。これにより、そこに移動したい他の動物が目を覚ますことができます。

私は両方をロックしようとしましたが、その結果、動物は明白な理由もなく彼らのトラックで死んで停止していました。少し説明するために、ここにコードを示します。

void move(dir direction)
{
    Integer tarX = ((direction==dir.east?(x+1):(direction==dir.west?(x-1):x))); // east->x+1/west->x-1/NS->x
    Integer tarY = ((direction==dir.north?(y-1):(direction==dir.south?(y+1):y))); //see above
    Animal an;
    synchronized(TileManager.getInstance().playField[tarX][tarY])
    {

            an = AnimalManager.getInstance().searchByXY(tarX, tarY);   
            while (an != null)
            {                    
                interact(an); //assume it's empty - if it isn't, it results in a death of target animal anyway                
                an = AnimalManager.getInstance().searchByXY(tarX, tarY); //possibly redundant?
                if (an != null) {
                    try {
                        TileManager.getInstance().playField[tarX][tarY].wait();
                    } catch (InterruptedException ex) {
                    }
                }
                an = AnimalManager.getInstance().searchByXY(tarX, tarY, dir.none);
            }
        synchronized(TileManager.getInstance().playField[x][y])
        {
                int prevX = x;
                int prevY = y;
                x = tarX;
                y = tarY;
                TileManager.getInstance().playField[prevX][prevY].notify();
                TileManager.getInstance().playField[x][y].notify();
        }
    }
}

ええ、それはめちゃくちゃです、私は知っています、そしてそれもあまりうまくいきません。誰かが何をすべきかについて何か考えがありますか?

4

1 に答える 1

0

このソリューションのパフォーマンスに問題がないかどうかを確認する必要がありますが、PlayFieldへの同期アクセスを取得するためにロックする必要があるある種の「アービター」オブジェクトを導入できます。

パターンは次のようになります。

private static final Object arbiter = new Object( );

void move(dir direction)
{
  ...
  TileManager tileManager = TileManager.getInstance( );

  synchronized( arbiter )
  {
    PlayField tarXtarYField = tileManager.playField[tarX][tarY];

    synchronized( tarXtarYField )
    {
      ...

      PlayField xyField = tileManager.playField[x][y];
      synchronized( xyField )
      {
        ...
        tileManager.playField[prevX][prevY].notify();
        xyField.notify();
      }
    }
  }
}

このパターンはデッドロックを回避するのに役立ちますが、基本的にプレイフィールドへのアクセスはオブジェクトを介してシリアル化されるため、移動が遅いゲームの代償としてarbiter、一度に1つのスレッドしか移動できません。

野原が広すぎず、動物の数が少なければ、パフォーマンスは許容範囲内である可能性があります。そうでない場合は、実際にこのプログラムを最初から書き直す必要があります。

于 2012-12-28T01:19:54.370 に答える