4

Java を使用したマルチスレッドは初めてです。私はいくつかの調査を行い、チュートリアルを読み、テストを行いましたが、この問題で立ち往生しています。基本的に、私はゲームのスケルトンをセットアップしています。メソッドを含むスレッド クラスであるメイン アクティビティ クラスが必要で、低速な操作 (ファイルの読み取りとコンテンツのバッファへのアンパック) を実行し、スレッドが必要です。 UI操作に反応するゲームループです。

まず、別のスレッドをインスタンス化して開始するメイン アクティビティ クラスがあります。

public class ExperimentsActivity extends Activity {

// This is just a container class with some member data such as ByteBuffers and arrays
TestClass tclass = new TestClass(this);

// Main looping thread
MainLoopThread loop;
Thread mainLoop;

// Start the main looping thread which will trigger the engine's operations
loop = new MainLoopThread(tclass);
mainLoop = new Thread(loop);
mainLoop.start();
loop.setRunning(true);

(...)
}

次に、MainLoopThreadゲーム ロジックのスレッドを実装するクラスがあります。

public class MainLoopThread implements Runnable  {

public boolean running;
private TestClass baseData;

// Thread for data loading/unpacking ( CLASS DEFINITION BELOW )
GFXUnpack dataUnpack;
Thread dataUnpackThread;

public MainLoopThread( TestClass testClassStructure ) {
    running = false;
    baseData = testClassStructure;
}

public void setRunning ( boolean run ) {
    if ( run == true )
    {
        // Launch the thread which manages loading and unpacking graphics
        dataUnpack = new GFXUnpack(baseData.filepack[0]);
        dataUnpackThread = new Thread(dataUnpack);
        dataUnpackThread.start();
        dataUnpack.setRunning(true);
        fileOpened = false;

        // Open the GFX packet file
        try {
            synchronized (this) {
                dataUnpack.setOperation(2);                     
                Log.d("MainLoopThread", "File opening : waiting...");
                while ( dataUnpack.fileOpened == false ) {
                    wait();
                }
                Log.d("MainLoopThread", "File opening wait completed");
            }

            if ( dataUnpack.outCode == -1 ) 
                    Log.d("MainLoopThread", "File opening error !!");
                else fileOpened = true;
                    Log.d("MainLoopThread", "File opening completed");
            } 
            catch ( Exception exp ) {
                Log.d("MainLoopThread", "File opening code exception !!" + exp);
            }
        }
        else if ( dataUnpack.running == true ) dataUnpack.setRunning(false);              running = run;
    }

    // ------------------------------------
    // Here is the main looping thread. All the events related to loading 
    // and unpacking graphics go here
    public void run() {
        while (running) {
            synchronized (this) {
              // ------ Read a GFX packet and update texture pixels
              if ( fileOpened == true ) {
                  try {
                      // ( Do some stuff... )
                      wait();
                  } catch ( Exception exp ) {
                  Log.d("MainLoopThread", "Exception thrown !! " + exp );
              }
          }
      } // ( Thread-out code removed. Anyway, it never passed here )
  }         

そして最後に、GFXUnpackSD カード上のファイルを開くコードを含むスレッド クラスが、SD カード内のものを読み取り、バッファに書き込みます。

public class GFXUnpack implements Runnable {
// -------------    
public boolean running = false;
private Filedata fdata;
private int operation = 0, parameter = 0;
public boolean fileOpened;
public int outCode;  // Used to signal the caller about the outcome of the operation
// ------------------------------
public GFXUnpack ( Filedata packetDataStructure ) {
    this.fdata = packetDataStructure;
}
// --------
public void setRunning ( boolean run ) {
    running = run;   operation = 0;  fileOpened = false;            
    outCode = 0;      parameter = 0;
}
// --------
public void setOperation ( int op ) {
    operation = op;
}
// ---
public void setOperation ( int op, int parm ) {
    operation = op;
    parameter = parm;
}
// ---------    
public synchronized void run() {
    while (running) {
        try {
      switch ( operation ) {
                case ( 2 ) :  // Open the gfx data file
                        ( ...do stuff... )
                        break;                  
                    }
                    // ---------
                    try {
                           ( ...Do some stuff here... )
                           Log.d("GFXUnpack", "Mapping file");
                           ( ...Do some stuff here... )
                           Log.d("GFXUnpack", "Mapped file");
                           fileOpened = true;
                           outCode = 1;
                    } catch ( Exception e ) {
                        Log.d("GFXUnpack", "File opening exception !! " + e);
                        outCode = -1;
                    }
                    finally {
                        operation = 0;       parameter = 0;
                        notifyAll();
                        Log.d("GFXUnpack", "Notified file opening");
                    }
                }
                break;
    // ----------------
            }
            // ----- Other cases here... 
        } finally {
        }
    }
}

上記を実行すると、デバッガーの出力は次のようになります。

MainLoopThread ファイルを開く: 待機中...
GFXUnpack マッピング ファイル
GFXUnpack マップされたファイル
GFXUnpack 通知されたファイルを開く

その後、アプリがハングし、強制終了する必要があります。(ブロック内の)notifyAll()run()メソッドを呼び出すので、呼び出し元のスレッド (MainLoopThread) が続行され、デバッガー メッセージ 'File opening completed' が表示されると思いましたが、代わりにアプリがハングします。GFXunpackfinally{}

なぜこれが起こっているのか、誰にもアイデアがありますか?

4

1 に答える 1

3

インスタンスは( のインスタンス)でMainLoopThread待機し、インスタンスは ( のインスタンス) で通知します。そのため、ノーティファイアは待機中のスレッドに通知しません。thisMainLoopThreadGFXUnpackthisGFXUnpack

2 つのオブジェクトは、同じオブジェクト インスタンスを使用して待機および通知する必要があります。さらに良いことに、java.util.concurrentこれらの使いにくい低レベルのメソッドではなく、パッケージからの高レベルの抽象化 (セマフォ、カウントダウンラッチなど) を使用する必要があります。

さらに、wait()偽のウェイクアップのために、ウェイクアップに必要な条件が実現されているかどうかを確認し、そうでない場合は再び待機を開始するループで常に呼び出す必要があります。

于 2012-11-17T17:45:03.307 に答える