2012-11-17 49 views
4

我是新的多線程與Java。我已經做了一些研究,閱讀教程,並完成測試,但我堅持這個問題。基本上,我設置了一個遊戲的骨架,我想要有主要的活動類,一個包含方法的線程類,執行緩慢的操作(讀取文件並將內容解包到緩衝區),並有一個線程是遊戲循環對UI操作做出反應。線程notall後notifyall()

首先,我有實例化和啓動一個單獨的線程的主要活動類:

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) 
    }   

最後,GFXUnpack線程類,其中包含打開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公告文件打開

然後,應用程序掛起,我不得不強行關閉它。我想,因爲我在方法GFXunpackfinally{}塊)中調用notifyAll()方法,調用者線程(MainLoopThread)會繼續,我會看到調試器消息'File opening completed',但應用程序掛起。

有沒有人有任何想法,爲什麼發生這種情況?

回答

3

MainLoopThread的實例等待上this(的MainLoopThread一個實例),並且GFXUnpack實例上this(的GFXUnpack一個實例)通知。所以通知程序不會通知等待的線程。

這兩個對象必須使用相同的對象實例來等待和通知。更好的是,您應該使用java.util.concurrent包中的更高級抽象,如信號燈,CountDownLatches等,而不是這些難以使用的底層方法。

而且,wait()應始終在循環中調用,以檢查喚醒所需的條件是否已實現,如果不是,則由於虛假喚醒而開始再次等待。

+0

謝謝JB,我會對你給我的方向做一些研究和測試! – Logicat

相關問題