最近在复习多线程,那就给大家讲解一下JAVA线程的终止的方式吧。

在 Java 中有以下 3 种方法可以终止正在运行的线程:
使用退出标志,通过更改标志,使线程正常退出,也就是让 run() 方法完成后线程中止。简单的说就是通过修改标志(变量的值)让run方法执行完。
使用 stop() 方法强行终止线程,但是不推荐使用这个方法,该方法已被弃用。
使用 interrupt 方法中断线程。
1. 使用标志位终止线程
在 run() 方法执行完毕后,该线程就终止了。但是在某些特殊的情况下,run() 方法会被一直执行;比如在服务端程序中可能会使用 while(true) { ... } 这样的循环结构来不断的接收来自客户端的请求。此时就可以用修改标志位while(false) { ... }的方式来结束 run() 方法。
public static void main(String[] args) { ServerTest serverTest = new ServerTest(); serverTest.start(); try { Thread.sleep(10); serverTest.setFlag(false); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}class ServerTest extends Thread{ //保证其他线程获取时都是最新值 public volatile boolean flag=true; public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } //重写run方法 @Override public void run() { System.out.println("开始"); while(flag) { System.out.println("xxxx"); } System.out.println("结束"); } }
结果
开始xxxxxxxx......结束
2、使用stop()方法强行结束
我们通过查看 API,我们会看到 java.lang.Thread 类型提供了一系列的方法如 start()、stop()、resume()、suspend()、destory()等方法来管理线程。但是除了 start() 之外,其它几个方法都被声名为已过时(deprecated)。

虽然 stop() 方法确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且该方法已被弃用,最好不要使用它。
JDK 文档中还引入用一篇文章来解释了弃用这些方法的原因:《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》
为什么弃用stop:
调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
3. 使用 interrupt() 中断线程
现在我们知道了使用 stop() 方式停止线程是非常不安全的方式,那么我们应该使用什么方法来停止线程呢?答案就是使用 interrupt() 方法来中断线程。
需要明确的一点的是:interrupt() 方法并不像在 for 循环语句中使用 break 语句那样干脆,马上就停止循环。调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程。
也就是说,线程中断并不会立即终止线程,而是通知目标线程,有人希望你终止。至于目标线程收到通知后会如何处理,则完全由目标线程自行决定。这一点很重要,如果中断后,线程立即无条件退出,那么我们又会遇到 stop() 方法的老问题。
事实上,如果一个线程不能被 interrupt,那么 stop 方法也不会起作用。
我们来看一个使用 interrupt() 的例子:


从输出的结果我们会发现 interrupt 方法并没有停止线程 t 中的处理逻辑,也就是说即使 t 线程被设置为了中断状态,但是这个中断并不会起作用,那么该如何停止线程呢?
这就需要使用到另外两个与线程中断有关的方法了:
public boolean Thread.isInterrupted() //判断是否被中断
public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态


在上面这段代码中,我们增加了 Thread.isInterrupted() 来判断当前线程是否被中断了,如果是,则退出 for 循环,结束线程。
这种方式看起来与之前介绍的“使用标志位终止线程”非常类似,但是在遇到 sleep() 或者 wait() 这样的操作,我们只能通过中断来处理了。
public static native void sleep(long millis) throws InterruptedException
Thread.sleep() 方法会抛出一个 InterruptedException 异常,当线程被 sleep() 休眠时,如果被中断,这会就抛出这个异常。
(注意:Thread.sleep() 方法由于中断而抛出的异常,是会清除中断标记的。)
public class test02 { public static void main(String[] args) { F f = new F(); f.start(); f.interrupt(); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("main结束"); }}class F extends Thread{ @Override public void run() { try { System.out.println("开始"); sleep(100000); System.out.println("结束"); } catch (InterruptedException e) { System.out.println("xxxxxxxxxxxxxxxx"); } } }