不推荐使用 stop、suspend、resume 这三个过期作废的方法,因为有可能会发生不可预料的结果而且出现错误后还比较难定位。
不推荐使用 Thread.stop() 的原因。这个方法是从外面让线程强制停止 ,如果停止的线程持有一个临界锁, 把一个对象置于一个不一致的状态(包含临界、持久化、游离),说白了就是造成数据不一致的结果。大多数情况下,停止一个线程使用 Thread.interrupt() 方法,但是这个方法不会终止一个正在运行状态的线程,还需要加入一些判断才能完成停止线程。
在Java中有3种方式停止正在运行的线程:
1、使用退出标志,正常退出;
2、使用 stop(), 强行终止;
3、使用 interrupt() 方法,中断线程;
interrupt() 初体验 一上来就按照下面这种方式运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ThreadInterrupt { public static void main (String[] args) throws InterruptedException { MyThread myThread = new MyThread (); myThread.start(); Thread.sleep(1000 ); myThread.interrupt(); System.out.println("mrdjun" ); } } class MyThread extends Thread { @Override public void run () { super .run(); for (int i = 0 ; i < 1000000 ; i++) { System.out.println("i=" + (i + 1 )); } } }
发现结果输出了 1000000 行,而且 mrdjun 还输出在了中间,说明 interrupt 并没有让线程停下来。
判断线程是否为停止状态 下面Java提供了两个判断线程是否为停止状态的方法。
public static boolean interrupted() :使用 Thread.interrupted() 测试当前线程是否已经中断,执行后清楚状态标志值为 false 的功能。
public boolean this.isInterrupted(): 测试 this 关键字所在类的对象是否已经中断,不清楚标志。
1 2 3 4 5 6 7 8 9 10 11 public class ThreadInterrupt { public static void main (String[] args) throws InterruptedException { MyThread myThread = new MyThread (); myThread.start(); Thread.sleep(1000 ); myThread.interrupt(); System.out.println("线程是否停止?" +myThread.isInterrupted()); System.out.println("线程是否停止?" +myThread.isInterrupted()); } }
补充一点:也可以使用 Thread.interrupted() 来判断当前线程是否已经中断,因为在 Thread.java 这个类中调用静态static方法的时候,大多数是针对 currentThread() 线程进行操作的。
1 2 3 4 5 6 7 8 9 public class ThreadInterrupt { public static void main (String[] args) throws InterruptedException { Thread.currentThread().interrupt(); System.out.println("线程是否停止?" + Thread.interrupted()); System.out.println("线程是否停止?" + Thread.interrupted()); System.out.println("END!" ); } }
出乎意料的是结果输出不一致,查看官方帮助文档中的 interrupted() 解释:
测试当前线程是否已经中断。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
isInterrupted() 的方法声明如下:
1 public boolean isInterrupted () ;
很显然,这个方法不是一个static方法,作用于这个方法的对象,如下。
1 2 3 4 5 6 7 8 9 10 11 public class ThreadInterrupt { public static void main (String[] args) throws InterruptedException { MyThread myThread = new MyThread (); myThread.start(); Thread.sleep(1000 ); myThread.interrupt(); System.out.println("线程是否停止?" + myThread.isInterrupted()); System.out.println("线程是否停止?" + myThread.isInterrupted()); System.out.println("END!" ); } }
综上所述,两者区别如下:
(1)Thread.interrupted() 测试线程是否已经中断,执行后具有清除状态标志值为false的功能;
(2)new Thread().isInterrupted() 测试线程Thread对象是否已经是中断状态,不清除状态标志;
能停止的线程——异常法 在main方法中两秒后调用 Thread 对象的 myThread.interrupt() 方法,在线程中的for循环中加入 if 判断后面的代码是否可以运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class ThreadInterrupt { public static void main (String[] args) throws InterruptedException { MyThread myThread = new MyThread (); myThread.start(); Thread.sleep(500 ); myThread.interrupt(); } } class MyThread extends Thread { @Override public void run () { super .run(); try { for (int i = 0 ; i < 5000000 ; i++) { if (interrupted()) { System.out.println("线程已经停止" ); throw new InterruptedException (); } System.out.println("i=" + (i + 1 )); } System.out.println("for循环外面的语句" ); } catch (InterruptedException e) { e.printStackTrace(); } } }
抛出异常方式详情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class ThreadInterrupt { public static void main (String[] args) { try { MyThread myThread = new MyThread (); myThread.start(); Thread.sleep(1000 ); myThread.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } } class MyThread extends Thread { @Override public void run () { super .run(); try { for (int i = 0 ; i < 5000000 ; i++) { if (interrupted()) { System.out.println("线程已经停止" ); throw new InterruptedException (); } System.out.println("i=" + (i + 1 )); } System.out.println("for循环外面的语句" ); } catch (Exception e) { System.out.println("抛出异常" ); e.printStackTrace(); } } }
通过下面的运行结果可以看出,线程终于被正确的停止了。
1 2 3 4 5 6 i=312961 i=312962 线程已经停止 抛出异常 java.lang.InterruptedException at com.fun.async.test.class03.MyThread.run(ThreadInterrupt.java:34 )
在 sleep 状态下停止线程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class SleepThreadInterrupt { public static void main (String[] args) { try { MyThread thread = new MyThread (); thread.start(); Thread.sleep(200 ); thread.interrupt(); System.out.println("complete!" ); } catch (InterruptedException e) { System.out.println("main catch" ); e.printStackTrace(); } } static class MyThread extends Thread { @Override public void run () { super .run(); try { System.out.println("run start ..." ); Thread.sleep(200000 ); System.out.println("run end!" ); } catch (InterruptedException e) { System.out.println("在sleep中停止,进入catch!" +this .isInterrupted()); e.printStackTrace(); } } } }
从下面的输出结果来看,如果线程在 sleep 状态下停止,则该线程会进入 catch 语句,并且清除停止状态值,变成false。
1 2 3 4 5 6 7 run start ... complete! 在sleep中停止,进入catch !false java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.fun.async.test.class03.SleepThreadInterrupt$MyThread.run(SleepThreadInterrupt.java:26 )