2011-04-14 96 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(); 
     } 
    } 
});