停止/销毁线程
我有一个服务启动一个线程和一个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();
}
,但它仍然无法正常工作,线程继续运行。任何帮助家伙?
为什么不使用AsyncTask?
任何时候都可以通过调用cancel(boolean)取消任务 。调用 这种方法将导致后续的 调用isCancelled()返回true。 调用此方法后, onCancelled(对象),而不是 onPostExecute(对象)将被doInBackground之后调用 (对象[]) 回报。为了确保任务 尽快取消,您 应经常检查isCancelled()定期从 doInBackground(对象[])的返回值 ,如果可能的话 (例如一个循环中。)
因为这个原因,我无法使用AsyncTask:“记住一个AsyncTask实例必须在UI线程上创建并且只能执行一次也非常重要”(developer.android.com/resources/articles/... )。我的线程/异步任务在一个服务上运行,所以它不会发生 - – foodman 2011-04-14 09:12:46
@foodman:我想你误解了他们想说的 - 这只是**如果你执行影响UI线程的操作'onPostExecute'等方法。如果你没有触及UI线程(因为你在一个服务中运行它),那么使用AsyncTask就可以了。 – 2011-04-14 09:28:11
备选答案
使用下面的代码:
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!");
}
}
}
您可能需要阅读以下内容:
- How do you kill a thread in Java?
- Thread Primitive Deprecation如已经Claszen
- http://www.devx.com/tips/Tip/31728指出 - 从这里基于我的代码,但也有一些问题与代码!
我认为你可以依靠捕捉异常而不检查异常终止,但我决定保持这种方式。
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();
}
}
}
他正在使用'doA()'函数的等效函数没有完全返回,因此'Thread'基本上挂在那个方法调用上。因此,它不会进入下一步,这将是'if(!abort)'调用。 – 2011-04-14 11:03:14
但是如果他调用thread.interrupt(),它应该引发一个将被try-catch子句捕获的异常。 – 2011-04-14 11:13:55
是的,我也曾想过,但他说他在'onDestroy()'中调用了'th.interrupt();'并且线程继续运行。 – 2011-04-14 11:49:10
线程destroy
和stop
方法固有的死锁倾向和不安全的。它们的存在也给了错觉,有可能是立即停止另一个线程,当别的东西告诉它的一些方法。
我明白你的想法,从你的角度来看他们是一个主线程,当这个线程还没有收到工作线程的响应时,你想杀死它并重启它,没有关心什么就看。但是,这些方法已被弃用的原因是你应该不在乎什么的线程可达。很多。
如果有什么的线程有大约以后需要使用一个变量的锁?如果一个线程打开文件句柄怎么办?在所有这些情况下,以及更多情况下,简单地在当前操作中停止线程会使事情变得糟糕 - 很可能您的应用程序只会进一步崩溃。
因此,为了使线程可中断或可取消或可停止,它必须自行管理它。如果一个线程或操作提供没有办法让自己被打断,那么你就不能中断它 - 假定这样做会不安全。
如果您运行的是字面上
public void run() {
doSomething();
}
那么有没有办法打断它。人们希望,如果doSomething
是一个长期的运作,有可能是一种方法,或者与它逐步互动的东西,如
public void run() {
while (running) {
MyParser.parseNext();
}
}
或能够通过参考指示线程是否被中断的变量传递或不,并希望该方法会在适当的位置自行中断。
记住一个blocking
操作被阻止。没有办法解决这个问题,你不能取消它。
感谢您的回复。目前我使用线程的唯一原因是因为doSomething()操作是异步的,并会将主线程挂在手机上,导致整个手机在此期间无法使用。它实际上不涉及任何我需要的变量,也不会与线程外部的任何变量交互。我会进一步研究你之前提到的AsyncTask – foodman 2011-04-15 01:47:25
我喜欢采取如下方法:
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();
}
最好使用全局变量stopThread,停止线程一旦变量更改为true。
btnStop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0){
stopThread = true;
}
});
public void run() {
while (!stopThread) {
//do something
}
}
我想创建和使用另一个线程沟通的最佳方式是使用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();
}
}
});
该链接基本上重新迭代我所面临的所有问题和约束。链接讲述如何使用interrupt()代替stop(),这正是我正在做的。 interrupt()的问题是它只能用于sleep(),wait()和join()。在我的代码中,挂起的行不是这些,它从来没有恢复,甚至在一个小时后。线程卡在那条线上,没有中断可以将其解救出来。 – foodman 2011-04-14 09:05:53