停止线程在java语言中并不像break语句那样干脆,还需要一些技巧性的处理。
停止一个线程意味着在线程处理完任务之前停止正在做的操作,也就是放弃当前的操作,虽然这看起来非常简单,但是必须做好防范措施,以便达到预期的效果。
停止一个线程可以使用Thread.stop()方法,但不推荐使用此方法,虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是被弃用作废的。
大多数情况下,停止一个线程使用Thread.interrupt()方法,但这个方法不会终止一个正在运行的线程,还需要加入一个判断才可以完成线程的停止。
在java中有3种方法可以使正在运行的线程终止运行:
- 使用退出标志使线程正常退出。
- 使用stop()方法强行终止线程,但是这个方法不推荐使用,因为stop()和suspend()、resume()一样,都是作废过期的方法,使用它们可能发生不可预料的结果。
- 使用interrupt()方法中断线程。
本示例将调用interrupt()方法来停止线程,但interrupt()方法的使用效果并不像for+break语句那样,马上就停止循环。调用interrupt()方法仅仅是在当前线程中做了一个停止的标记,并不是真正停止线程。
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 500000; i++) {
System.out.println("i=" + (i + 1));
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
System.out.println("zzzzzzzzzzzzzzzzzz");
}
}
调用interrupt()方法并没有将线程停止,那如何停止线程呢?
判断线程是否为停止状态 interrupted()方法Thread.java类提供了两个判断方法来判断线程的状态是否是停止的:
- public static boolean interrupted():测试currentThread()是否已经中断。
- public boolean this.isInterrupted():测试this关键字所在类的对象是否已经中断。
那这两个方法有什么区别呢?先来看方法this.isInterrupted()方法的解释:测试当前线程是否已经中断,当前线程是指运行this.interrupted()方法的线程。如下代码所示:
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 5000; i++) {
System.out.println("i=" + (i + 1));
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(10);
thread.interrupt();
System.out.println("是否停止1?="+thread.interrupted());
System.out.println("是否停止2?="+thread.interrupted());
}
}
output: i=517 i=518 i=519 i=520 i=521 是否停止1?=false i=522 是否停止2?=false i=523 i=524 i=525 i=526 i=527
虽然通过在thread对象上调用代码:
thread.interrupt()
然后又使用代码:
thread.interrupted()
判断线程是否中断,返回false,因为interrupted()方法返回当前线程是否中断,当前线程是main线程,从未中断过,所以返回false。
最好使用Thread.interrupted(),因为interrupted()为静态方法,大多数是针对currentThread()线程进行操作的。
public class Run2 {
public static void main(String[] args) {
Thread.currentThread().interrupt();
System.out.println("是否停止1?=" + Thread.interrupted());
System.out.println("是否停止2?=" + Thread.interrupted());
System.out.println("end!");
}
}
output: 是否停止1?=true 是否停止2?=false end!
为啥第一个interrupted()方法判断了当前线程是否停止状态,第二个却返回false呢?
interrupted()方法在官方文档的解释为:
isInterrupted()方法判断当前线程是否已经中断。线程的中断状态由该方法清除。
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(10);
thread.interrupt();
System.out.println("是否停止1?="+thread.isInterrupted());
System.out.println("是否停止2?="+thread.isInterrupted());
}
}
output: i=542 i=543 i=544 i=545 i=546 i=547 是否停止1?=true i=548 是否停止2?=true i=549 i=550 i=551 i=552
从结果中可以看出,isInterrupted()方法并未清除状态标志,不具有此功能,所以输出两个true。
综上:
- interrupted():测试当前线程是否已经是中断状态,执行后具有清除状态标志值的功能。
- isInterrupted():测试线程Thread对象是否已经是中断状态,不清除状态标志。
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 5000; i++) {
if(this.isInterrupted()){
System.out.println("已经是停止状态了!我要退出了!");
break;
}
System.out.println("i=" + (i + 1));
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(10);
thread.interrupt();
System.out.println("end");
}
}
output: i=59 i=60 i=61 i=62 i=63 i=64 i=65 i=66 i=67 i=68 i=69 i=70 i=71 i=72 i=73 已经是停止状态了!我要退出了! end
上面代码虽然停止了线程,但如果for语句下面还有语句,那么程序还是会继续运行。
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 5000; i++) {
if(this.isInterrupted()){
System.out.println("已经是停止状态了!我要退出了!");
break;
}
System.out.println("i=" + (i + 1));
}
System.out.println("我被输出,线程并未停止");
}
}
output: i=32 i=33 i=34 i=35 i=36 i=37 i=38 i=39 i=40 i=41 i=42 end 已经是停止状态了!我要退出了! 我被输出,线程并未停止
如何解决语句继续执行的问题呢?使用异常,如下代码所示:
public class MyThread extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 5000; i++) {
if(this.isInterrupted()){
System.out.println("已经是停止状态了!我要退出了!");
throw new InterruptedException();
}
System.out.println("i=" + (i + 1));
}
System.out.println("我被输出,线程并未停止");
}catch (InterruptedException e){
System.out.println("线程中断,抛出异常,被捕获");
e.printStackTrace();
}
}
}
output: i=94 i=95 i=96 i=97 java.lang.InterruptedException i=98 end 已经是停止状态了!我要退出了! at com.example.threadcore.MyThread.run(MyThread.java:16) 线程中断,抛出异常,被捕获
由程序运行结果可以看出,线程终于被正确停止了。这就是使用interrupt()方法中断线程。
在sleep状态下停止线程public class MyThread extends Thread {
@Override
public void run() {
super.run();
try {
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("在沉睡中被停止,进入catch" + this.isInterrupted());
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(10);
thread.interrupt();
System.out.println("end");
}
}
output: run begin end 在沉睡中被停止,进入catch false java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.example.threadcore.MyThread.run(MyThread.java:14)
从运行结果来看,如果线程在sleep状态下停止,则该线程会进入catch语句,并且清除停止状态值,变成false。
以上示例是先调用sleep()方法,再调用interrupt()方法停止线程,还有一个反操作,即先调用interrupt()方法,再调用sleep()方法,这种情况下也会出现异常。
public class MyThread extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 10000; i++) {
System.out.println("i= " + (i + 1));
}
System.out.println("run begin");
Thread.sleep(200000);
System.out.println("run end");
} catch (InterruptedException e) {
System.out.println("先停止,再遇到了sleep,进入catch " + this.isInterrupted());
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
thread.interrupt();
System.out.println("end");
}
}
output: i= 9994 i= 9995 i= 9996 i= 9997 i= 9998 i= 9999 i= 10000 run begin 先停止,再遇到了sleep,进入catch false java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.example.threadcore.MyThread.run(MyThread.java:17)
综上,不管调用的顺序,只要interrupt()和sleep()方法碰到一起就会出现异常:
- 在sleep状态执行interrupt()方法会出现异常。
- 调用interrupt()方法给线程打了中断标记,再执行sleep()方法也会出现异常。
虽然使用return较“抛异常”法在代码结构上可以更加方便地实现线程的停止,不过还是建议使用“抛异常”法,因为在catch块中可以对异常的信息进行统一的处理。



