停止/销毁线程

时间:2011-04-14 07:47:06

标签: android multithreading service

我有一个启动Thread和Runnable的服务。

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

t.start();

线程的原因是执行异步任务 doSomething()。现在让我们不要担心其他类AsyncTask。我已经尝试过它并不适用于我的情况。编辑:我不能使用AsyncTask,因为它仅适用于UI线程。这段代码必须在服务中运行,所以nope,没有AsyncTask :(

doSomething()包含一些外部库,所以我遇到的问题是它可能挂在其中一个命令上,而不返回任何值(因此甚至不能进行错误检查)

为解决这个问题,我希望在某些时候破坏服务。

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

这很好用,很容易在手机上验证。但是,即使产生它的服务被销毁,上面创建的Thread也将继续运行。

因此,我正在寻找在服务的 onDestroy()中插入的正确命令,这将为我清理线程。

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

都被折旧并导致应用程序崩溃。

我从某个地方获取了这段代码

@Override
public void onDestroy() {

    Thread th = t;
    t = null;

    th.interrupt();

    super.onDestroy();
}

但它仍然不起作用,线程继续运行。有帮助吗?

7 个答案:

答案 0 :(得分:11)

线程destroystop方法本质上容易出现死锁,并且不安全。它们的存在也给人一种幻觉,即当其他东西告诉它时,可能会有某种方法立即停止另一个线程。

我理解你的想法,从你的观点来看,他们是一个主线程,当这个线程在一段时间没有收到来自它的工作线程的响应时你想杀死它并重启它,没有关心它是什么。但是这些方法被弃用的原因是你应该关心线程的用途。很多。

如果线程锁定了您稍后需要使用的变量,该怎么办?如果一个线程打开了文件句柄怎么办?在所有这些情况下,还有更多情况下,简单地停止当前操作的线程会让事情变得一团糟 - 很可能你的应用程序只会在线路上崩溃。

因此,为了使线程可以中断或取消或可停止,它必须自己管理。如果线程或操作无法自行中断,那么就不能打断它 - 假设这样做会不安全。

如果你运行就是字面意思

public void run() {
   doSomething();
}

然后没有办法打断它。人们希望,如果doSomething是一个很长的操作,那么可能有一种方法可以通过

之类的方式逐步与它进行交互。
public void run() {
   while (running) {
       MyParser.parseNext();
   }
}

或者能够通过引用传入一个变量来指示线程是否被中断,并且希望该方法能够在适当的位置中断自己。

请记住blocking操作正在阻止。没有办法解决这个问题,你无法在中途取消它。

答案 1 :(得分:2)

替代答案

使用以下代码:

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!");
       }
    }
}

您可能需要阅读以下内容:

我认为你可以依靠捕获异常而不是检查中止但我决定保持这种方式。

<强>更新

我在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(); 
        }
    }
}

答案 2 :(得分:1)

您是否查看了Java Thread Primitive Deprecation API JavaDoc中引用的Thread文档。你会找到一些提示来处理你的问题。

答案 3 :(得分:1)

为什么不使用AsyncTask

  

任务可以随时取消   调用cancel(boolean)。调用   这种方法会引起后续的   调用isCancelled()返回true。   调用此方法后,   onCancelled(Object),而不是   将调用onPostExecute(Object)   在doInBackground之后(Object [])   回报。确保完成任务   你尽快取消了   应该经常检查返回值   ofCancelled()定期来自   doInBackground(Object []),如果可能的话   (例如在循环内部。)

答案 4 :(得分: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();
    }
}

on service onDestroy只需释放stopEvent:

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

    super.onDestroy();
}

答案 5 :(得分:0)

最好使用全局变量stopThread,一旦变量变为true,就停止线程。

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


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

答案 6 :(得分: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();
        }
    }
});

停止和启动线程的示例:

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