问题描述
|
我有一个可以像这样启动线程和可运行对象的服务。
t = new Thread(new Runnable() {
public void run() {
doSomething();
}
});
t.start();
@H_502_2@
该线程的原因是要执行异步任务doSomething()。现在,不用担心其他类AsyncTask。我已经尝试过了,但不适用于我的情况。编辑:我不能使用AsyncTask,因为它仅用于UI线程。这段代码必须在Service内部运行,所以没有,没有AsyncTask :(
doSomething()包含一些外部库,因此我遇到的问题是它可以潜在地挂在命令之一上,而无需返回任何值(因此甚至无法进行错误检查)
要变通解决此问题,我将在某个时间点销毁服务。
stopService(new Intent(\"net.MyService.intent));
@H_502_2@
这可以正常工作,并且可以在电话上轻松验证。但是,即使创建它的服务被销毁,上面创建的线程也将继续运行。
因此,我正在寻找要插入到Service \的onDestroy()中的正确命令,该命令将为我清理线程。
t.destroy();
t.stop();
@H_502_2@
都已贬值,并导致应用程序崩溃。
我从某处获取了这段代码
@Override
public void onDestroy() {
Thread th = t;
t = null;
th.interrupt();
super.onDestroy();
}
@H_502_2@
但是它仍然不起作用,线程继续运行。有帮助吗?
解决方法
线程
destroy
和stop
本质上容易死锁并且不安全。它们的存在还给人一种幻觉,即当有其他人告诉别人时,可能会有某种方式立即停止另一个线程。
我理解您的想法,从您的角度来看,它们是一个主线程,并且当您想杀死它并重新启动它时,如果该线程在一段时间内未收到其工作线程的响应,关心它在做什么。但是不赞成使用这些方法的原因是您应该注意线程的作用。很多。
如果线程在您以后需要使用的变量周围具有锁,该怎么办?如果线程打开了文件句柄怎么办?在所有这些情况下,甚至更多的情况下,仅在当前操作中停止线程就会使事情变得一团糟-很可能您的应用程序会进一步崩溃。
因此,为了使线程可中断,可取消或可停止,它必须自己进行管理。如果线程或操作无法中断自身,则您将无法中断-假定这样做是不安全的。
如果你可以运行的话
public void run() {
doSomething();
}
那么就没有办法打断它。有人希望,如果“ 7”是一个长时间的操作,可能会有一种方法与之交互,例如
public void run() {
while (running) {
MyParser.parseNext();
}
}
或能够通过引用传递指示线程是否被中断的变量,并希望该方法可以在适当的位置中断自身。
请记住,ѭ9操作已被阻止。无法解决该问题,您无法部分取消它。
,替代答案
使用以下代码:
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!\");
}
}
}
您可能需要阅读以下内容:
您如何杀死Java中的线程?
Claszen已经指出的线程原始弃用
http://www.devx.com/tips/Tip/31728-从这里基于我的代码,但是代码存在一些问题!
我认为您可以依靠捕获异常而不检查中止,但是我决定保持这种状态。
更新
我已经在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();
}
}
}
,您是否检查了Thread API JavaDoc中引用的Java Thread Primitive Deprecation文档。您会发现一些提示来解决您的问题。
,为什么不使用AsyncTask?
可以通过以下方式随时取消任务
调用cancel(boolean)。调用中
此方法将导致后续
调用isCancelled()返回true。
调用此方法后,
onCancelled(Object),而不是
onPostExecute(Object)将被调用
在doInBackground(Object [])之后
返回。确保任务是
尽快取消,您
应该经常检查返回值
的isCancelled()的周期
如果可能,请执行doInBackground(Object [])
(例如在循环内。)
,我喜欢采用以下方法:
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();
}
}
});
停止和启动线程的示例:
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();
}
}
});