线程是你在Android中避不开的一个话题。
因为Android后期版本对主线程不允许运行耗时操作的规定,你新开线程的几率比起java,大大的提升了。
这样就会碰到一个问题,当你开启线程,在线程没有运行完的时候,想要结束这个线程,要怎么操作呢?
标志位结束线程
这是一种我们很容易理解的结束方式。设置一个标志位,当你想要结束线程的时候,就把这个标志位的状态改变。
直接看代码,更容易理解:
private class myThread extends Thread
{
volatile boolean isStop=false;
@Override
public void run() {
while(!isStop)
{
try {
Thread.sleep(3000);
Log.i(tag, "每3秒钟,运行一次....");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
这里的isStop就是标志位,当你要结束这个线程时,将isStop设置为true。这样就结束了该线程的运行。
中断方式结束线程
Interrupt,翻译为中文就是中断。
写法如下:
private class InterruptThread extends Thread
{
@Override
public void run() {
Log.i(tag, "Interrupt的状态:"+isInterrupted());
while(!isInterrupted())
{
try {
Thread.sleep(5*1000);
Log.i(tag, "Interrupt的状态(sleep后):"+isInterrupted());
Log.i(tag, "Interrupt中断方式...每5秒运行一次");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.i(tag, "Interrupt的状态(catch后):"+isInterrupted());
break;
}
}
}
}
当你这么定义一个thread的时候,你可以通过以下语句结束线程:
interruptThread.interrupt();
这种写法比起第一种有几个要注意的地方:
1、看log中打印的Interrupt的状态,运行后,可以看出,所以的isInterrupted(),状态都为false;无论是进入while中、sleep前后、还是catch中。
2、Thread.interrupt(),其实只是设置了该线程的中断标志,本身并不会主动的去中断这个线程;
3、从第2点以及对interrupt的解释,可以知道Interrupt是一种协作机制。Thread.interrupt()后,还需要Thread线程本身处理interrupt的逻辑。因此需要在我们catch中,我们直接break操作,退出这个线程。
那么,为什么log中打印的interrupt的状态都是false呢?
这里,就需要先看看interrupt相关的几个方法:interrupt(),这个方法是用于设置线程的标志位为中断;isInterrupted(),这个是用来判断线程是否中断;interrupted(),这个在我们上方的函数中是没有看到的,但是有对它的隐式调用,当调用这个方法时,线程的中断标志又重新变为false。
因为以上的原因,我们将Interrupt的线程写成上方的样子。在未进入阻塞线程前,用是否中断标志来判断是否退出线程;在进入阻塞线程后,用抛出异常的方式来结束这个线程。
与第一种方式相比,这种interrupt的方式可能不太符合大家的线性思维,但这确实也是一种有效的方法。
stop方式结束线程
这个应该是我们结束线程的第一反应,但这是不推荐使用的。因为我们在用了这个方法后,经常会发现,它有时并不能及时的关闭线程,并可能造成其他的意外。
这是挺早就被android(或者说java)弃用的一种方法。网上有各种解释,比较权威的就是:
1. 即刻抛出ThreadDeath异常,在线程的run()方法内,任何一点都有可能抛出ThreadDeath Error,包括在catch或finally语句中。
2. 会释放该线程所持有的所有的锁,而这种释放是不可控制的,非预期的。
想要详细了解的朋友,可以自行去网上查找说明。或者看它源码。