2011-04-14 94 views
17

我有一個服務啓動一個線程和一個Runnable像這樣。停止/銷燬線程

t = new Thread(new Runnable() { 
    public void run() { 
     doSomething(); 
    } 
}); 

t.start(); 

的原因線程是執行一個異步任務doSomething的()。現在不要擔心其他類AsyncTask。我已經嘗試過了,它不適合我的情況。編輯:我不能使用AsyncTask,因爲它只用於UI線程。這一段代碼具有到服務內操作,所以不,不的AsyncTask :(

doSomething的()包含一些外部庫,所以我遇到的問題是,它可以潛在地在其中一個命令被懸掛,不返回任何值(因此沒有錯誤檢查,甚至可以做到)

要解決這個問題,我會想,在某個時間點,摧毀服務。

stopService(new Intent("net.MyService.intent)); 

這工作得很好,是很容易在手機上驗證,但是,上面創建的線程即使在t時也會繼續運行他產生的服務被破壞了。

我正在尋找正確的命令來插入服務的onDestroy()這將清理線程給我。

t.destroy(); 
t.stop(); 

都折舊並導致應用程序崩潰。

我把這個代碼從某處

@Override 
public void onDestroy() { 

    Thread th = t; 
    t = null; 

    th.interrupt(); 

    super.onDestroy(); 
} 

,但它仍然無法正常工作,線程繼續運行。任何幫助傢伙?

回答

1

您是否檢查Thread API JavaDoc中引用的Java Thread Primitive Deprecation文檔。你會發現一些提示來處理你的問題。

+3

該鏈接基本上重新迭代我所面臨的所有問題和約束。鏈接講述如何使用interrupt()代替stop(),這正是我正在做的。 interrupt()的問題是它只能用於sleep(),wait()和join()。在我的代碼中,掛起的行不是這些,它從來沒有恢復,甚至在一個小時後。線程卡在那條線上,沒有中斷可以將其解救出來。 – foodman 2011-04-14 09:05:53

1

爲什麼不使用AsyncTask

任何時候都可以通過調用cancel(boolean)取消任務 。調用 這種方法將導致後續的 調用isCancelled()返回true。 調用此方法後, onCancelled(對象),而不是 onPostExecute(對象)將被doInBackground之後調用 (對象[]) 回報。爲了確保任務 儘快取消,您 應經常檢查isCancelled()定期從 doInBackground(對象[])的返回值 ,如果可能的話 (例如一個循環中。)

+2

因爲這個原因,我無法使用AsyncTask:「記住一個AsyncTask實例必須在UI線程上創建並且只能執行一次也非常重要」(developer.android.com/resources/articles/... )。我的線程/異步任務在一個服務上運行,所以它不會發生 - – foodman 2011-04-14 09:12:46

+1

@foodman:我想你誤解了他們想說的 - 這只是**如果你執行影響UI線程的操作'onPostExecute'等方法。如果你沒有觸及UI線程(因爲你在一個服務中運行它),那麼使用AsyncTask就可以了。 – 2011-04-14 09:28:11

1

備選答案

使用下面的代碼:

MyThread thread;  // class field 

創建並啓動就像你現在做的那樣。

thread = new MyThread(); 
thread.start(); 

當服務被銷燬, 「信號」 線程退出

public void onDestroy() { 
    // Stop the thread 
    thread.abort = true; 
    thread.interrupt(); 
} 

這裏是線程執行

//another class or maybe an inner class 
class MyThread extends Thread { 
    syncronized boolean abort = false; 

    //ugly, I know 
    public void run() { 
     try { 
      if(!abort) doA(); 
      if(!abort) doB(); 
      if(!abort) doC(); 
      if(!abort) doD(); 
     } catch (InterruptedException ex) { 
      Log.w("tag", "Interrupted!"); 
     } 
    } 
} 

您可能需要閱讀以下內容:

我認爲你可以依靠捕捉異常而不檢查異常終止,但我決定保持這種方式。

UPDATE

我已經看到了這個樣品中codeguru

public class Worker implements Runnable { 
    private String result; 
    public run() { 
     result = blockingMethodCall(); 
    } 
    public String getResult() { 
     return result; 
    } 
} 

public class MainProgram { 
    public void mainMethod() { 
     ... 
     Worker worker = new Worker(); 
     Thread thread = new Thread(worker); 
     thread.start(); 
     // Returns when finished executing, or after maximum TIME_OUT time 
     thread.join(TIME_OUT); 
     if (thread.isAlive()) { 
      // If the thread is still alive, it's still blocking on the methodcall, try stopping it 
      thread.interrupt(); 
      return null; 
     } else { 
      // The thread is finished, get the result 
      return worker.getResult(); 
     } 
    } 
} 
+0

他正在使用'doA()'函數的等效函數沒有完全返回,因此'Thread'基本上掛在那個方法調用上。因此,它不會進入下一步,這將是'if(!abort)'調用。 – 2011-04-14 11:03:14

+0

但是如果他調用thread.interrupt(),它應該引發一個將被try-catch子句捕獲的異常。 – 2011-04-14 11:13:55

+0

是的,我也曾想過,但他說他在'onDestroy()'中調用了'th.interrupt();'並且線程繼續運行。 – 2011-04-14 11:49:10

9

線程destroystop方法固有的死鎖傾向和不安全的。它們的存在也給了錯覺,有可能是立即停止另一個線程,當別的東西告訴它的一些方法。

我明白你的想法,從你的角度來看他們是一個主線程,當這個線程還沒有收到工作線程的響應時,你想殺死它並重啓它,沒有關心什麼就看。但是,這些方法已被棄用的原因是你應該不在乎什麼的線程可達。很多。

如果有什麼的線程有大約以後需要使用一個變量的鎖?如果一個線程打開文件句柄怎麼辦?在所有這些情況下,以及更多情況下,簡單地在當前操作中停止線程會使事情變得糟糕 - 很可能您的應用程序只會進一步崩潰。

因此,爲了使線程可中斷或可取消或可停止,它必須自行管理它。如果一個線程或操作提供沒有辦​​法讓自己被打斷,那麼你就不能中斷它 - 假定這樣做會不安全。

如果您運行的是字面上

public void run() { 
    doSomething(); 
} 

那麼有沒有辦法打斷它。人們希望,如果doSomething是一個長期的運作,有可能是一種方法,或者與它逐步互動的東西,如

public void run() { 
    while (running) { 
     MyParser.parseNext(); 
    } 
} 

或能夠通過參考指示線程是否被中斷的變量傳遞或不,並希望該方法會在適當的位置自行中斷。

記住一個blocking操作被阻止。沒有辦法解決這個問題,你不能取消它。

+0

感謝您的回覆。目前我使用線程的唯一原因是因爲doSomething()操作是異步的,並會將主線程掛在手機上,導致整個手機在此期間無法使用。它實際上不涉及任何我需要的變量,也不會與線程外部的任何變量交互。我會進一步研究你之前提到的AsyncTask – foodman 2011-04-15 01:47:25

0

我喜歡採取如下方法:

class MyHandler extends Handler { 
    final Semaphore stopEvent = new Semaphore(0); 

    @Override 
    public void handleMessage(Message msg) { 
     try { 
      while (!stopEvent.tryAcquire(0, TimeUnit.SECONDS)) { 
       doSomething(); 

       if (stopEvent.tryAcquire(SLEEP_TIME, TimeUnit.MILLISECONDS)) { 
        break; 
       } 
      } 
     } catch (InterruptedException ignored) { 
     } 

     stopSelf(); 
    } 
} 

在服務的onDestroy只要鬆開stopEvent:

@Override 
public void onDestroy() { 
    myHandler.stopEvent.release(); 
    myHandler = null; 

    super.onDestroy(); 
} 
0

最好使用全局變量stopThread,停止線程一旦變量更改爲true。

btnStop.setOnClickListener(new OnClickListener() {   
     @Override 
     public void onClick(View arg0){ 
      stopThread = true; 
     } 
    }); 


public void run() { 
     while (!stopThread) { 
      //do something 
     } 
} 
0

我想創建和使用另一個線程溝通的最佳方式是使用AsyncTask。下面有一個示例:

public class Task extends AsyncTask<Void, Void, Void> { 

    private static final String TAG = "Task"; 

    private boolean mPaused; 

    private Runnable mRunnable; 

    public Task(Runnable runnable) { 
     mRunnable = runnable; 
     play(); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     while (!isCancelled()) { 
      if (!mPaused) { 

       mRunnable.run(); 
       sleep(); 
      } 
     } 
     return null; 
    } 

    private void sleep() { 
     try { 
      Thread.sleep(10); 
     } catch (InterruptedException e) { 
      Log.w(TAG, e.getMessage()); 
     } 
    } 

    public void play() { 
     mPaused = false; 
    } 

    public void pause() { 
     mPaused = true; 
    } 

    public void stop() { 
     pause(); 
     cancel(true); 
    } 

    public boolean isPaused() { 
     return mPaused; 
    } 

} 

您現在可以輕鬆地使用這個類,並通過書面形式啓動線程:

Task task = new Task(myRunnable); 
task.execute((Void) null); 

伴隨着這一點,你可以很容易地暫停或循環停止線程:

mButton.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     if (task.isPaused()) { 
      task.play(); 
     } else { 
      task.pause(); 
     } 
    } 
}); 

停止和ST的例子:暫停和播放線程的

例藝術線程:

mButton.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     if (task.isCancelled()) { 
      task = new Task(myRunnable); 
      task.execute((Void) null); 
     } else { 
      task.stop(); 
     } 
    } 
});