停止线程在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语句停止线程的缺点和解决方案
虽然使用return较“抛异常”法在代码结构上可以更加方便地实现线程的停止,不过还是建议使用“抛异常”法,因为在catch块中可以对异常的信息进行统一的处理。