在我们平时实际开发中我们不可避免会使用到多线程,停止运行中的线程是不可避免的会在我们的项目中遇见过。关于线程的停止,我所知道的分两种情况来处理:
1. 一种停止处于运行态的多线程;
2.一种停止可处于阻塞状态的多线程。
首先,在运行状态下的多线程处理,这种情况会比较容易处理,常用处理如下:
public class Program {
public static void main(String[] args) {
StopTask sTask = new StopTask();
new Thread(sTask).start();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
sTask.end();
}
}
class StopTask implements Runnable{
private boolean stop = false;//此处用volatile修饰stop变量的话,end 方法就没有必要同步实现。简单说,在多线程环境下volatitle虽然没有互斥访问效果,但是它可以保证任何一个线程读写该域的时候都将看到最近刚刚写入的值。Ps:注意,volatitle只对原子操作保证同步效果,如:i +=1;不能保证该短语执行同步,应为该操作至少由两个原子操作(读i的值,i值写入+1)组成。
public synchronized void end(){
this.stop = true;
}
@Override
public void run() {
int num = 0;
while(!stop){
num++;
System.out.println("正在生产数字"+num);
}
System.out.println("Task is end");
}
}
第二种情况,当线程处于阻塞状态下,停止线程。
一开始Java库提供stop()方法来停止线程,但是该方法已经被废止。因为它不释放线程获取的锁,并如果线程处于不一致的状态,其他任务可以在这种状态下浏览并修改他们,这个产生的问题微妙难以发现。
如果现在在如下场景,当我们的线程正在使用某一项系统资源时候,我们中断被阻塞的线程,可能需要清理资源。因此,在任务run()打断,会抛出异常,我们在捕获异常来停止线程,虽然,我个人感觉我们用异常来处理线程中断有点搓,但是,我们在特点的异常catch子句来处理,并且可以正确清理资源,也不失为一种解决方式。
所以,我们在当线程中断的时候,我们可以通过中断异常的方式停止线程,代码如下:
class StopTask implements Runnable{
@Override
public void run() {
try {
//业务操作
Thread.sleep(1);
} catch (InterruptedException e) {
System.out.println("中断状态"+ Thread.currentThread().isInterrupted());
}
System.out.println("Task is end");
}
}
当前如果我们的线程不是处于中断状态,我们该怎样退出线程的run()方法来退出线程。通过学习interrupt()方法,我们指导我们调用interrupt()方法的时候,中断发生的唯一时刻是在任务要进入阻塞状态,或者已经在阻塞操作内部。当我们的线程不是处于中断状态,我们必须再想办法来退出线程的run方法。通过了解interrupt方法,我们知道interrupt()方法可以设置线程的中断状态,当我们的线程没有发生阻塞的时候,我们可以通过检查线程的中断状态来退出线程。处理流程如下所示:
中断实现如下:
public class Program {
public static void main(String[] args) throws InterruptedException {
StopTask sTask = new StopTask();
Thread t = new Thread(sTask);
t.start();
Thread.sleep(3);
t.interrupt();
}
}
class StopTask implements Runnable{
@Override
public void run() {
int num = 0;
try {
while(!Thread.currentThread().isInterrupted()){//检查中断状态
num++;
System.out.println("正在生产数字"+num);
Thread.sleep(1);
System.out.println("中断状态"+ Thread.currentThread().isInterrupted());
}
} catch (InterruptedException e) { //阻塞状态下调用interrput()方法,线程抛出异常InterruptedException,我们在此捕捉异常来中断线程。
System.out.println("中断状态"+ Thread.currentThread().isInterrupted());
}
System.out.println("Task is end");
}
}
以上带代码为包含可阻塞装填线程的停止实现例子。
在此,还要补充一点,我们调用interrupted不仅可以检查线程中断状态,不仅可以告诉你interrupt()是否被调用过,还可以清除中断状态。同样在抛出InterruptedException异常时候,也可以清除中断状态。由此,我们很容易知道以下一种写法的中断线程的方式为什么经常不能让线程停止。错误示例代码如下:
public class Program {
public static void main(String[] args) throws InterruptedException {
StopTask sTask = new StopTask();
Thread t = new Thread(sTask);
t.start();
Thread.sleep(3);
t.interrupt();
}
}
class StopTask implements Runnable{
@Override
public void run() {
int num = 0;
while(!Thread.currentThread().isInterrupted()){
num++;
System.out.println("正在生产数字"+num);
try {
Thread.sleep(100);
System.out.println("中断状态"+ Thread.currentThread().isInterrupted());
} catch (InterruptedException e) {
System.out.println("中断状态"+ Thread.currentThread().isInterrupted());
}
}
System.out.println("Task is end");
}
}
以上代码我们知道,当我们在设置线程不同的睡眠时间的时候,我们的线程经常会出现线程没有中断的情况。出现这种情况的原因在,当我们在阻塞状态下,我们调用interrupt()方法,我们线程抛出InterruptedException异常时候,我们的中断状态被清除了,所有当while(!Thread.currentThread().isInterrupted())判断线程中断状态是否设置,我们的循环还会继续下去,所有,我们的线程根本停不下来。
转载请注明出处: http://blog.csdn.net/johnnyz1234/article/details/41790823