Java: Java终止线程的几种方式
首先说明,使用stop方法终止的方式已经在很久之前就被废弃了,在加锁的情况下有可能会造成死锁,这里不做讨论。
1. 使用标志位终止线程
在run()方法执行完毕后,该线程就终止了。但是在某些特殊的情况下,希望run()方法中的代码一直循环执行。比如在服务端程序中可能会使用 while(true) { ... } 这样的循环结构来不断的接收来自客户端的请求。此时就可以用修改标志位的方式来结束 run() 方法。例:
public class ServerThread extends Thread { //volatile修饰符用来保证其它线程读取的总是该变量的最新的值 public volatile boolean exit = false; @Override public void run() { ServerSocket serverSocket = new ServerSocket(8080); while(!exit){ serverSocket.accept(); //阻塞等待客户端消息 ... } } public static void main(String[] args) { ServerThread t = new ServerThread(); t.start(); ... t.exit = true; //修改标志位,退出线程 } }
Note:一定要给标志位加上volatle 关键字!详细原因可参考:https://www.cnblogs.com/yongdaimi/p/9566332.html 或者 https://www.cnblogs.com/dolphin0520/p/3920373.html 。
2. 使用interrupt()方法来终止线程
interrupt()方法用于中断线程,调用该方法的线程状态将会被置为“中断状态”。
Note: 线程中断仅仅是置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。java中的那些支持线程中断的方法(也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。
调用这种方式去终止的线程存在两种情况:
第一种情况:该线程循环执行不会存在阻塞
比如,在while 循环中循环打印一句话:这样的话调用interrupt()会立即终止该线程。例:
package com.yongdaimi.java.demo; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Test3 { public static void main(String[] args) { NotInterruptThread mNotInterruptThread = new NotInterruptThread(); mNotInterruptThread.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } mNotInterruptThread.interrupt(); } static class NotInterruptThread extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("=============NotInterruptThread execute... ============="); } } } }
运行结果:
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
5 秒后,打印就会停止。
第二种情况:该线程循环执行存在阻塞状态
比如,在线程中存在sleep()、await()、wait(long) 这种能够抛出:interruptedException 异常的方法,这种情况调用interrupt()方法后将会触发这些异常,可以选择在触发异常后调用break来终止线程。例:
package com.yongdaimi.java.demo; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Test3 { private static Object sLock = new Object(); private static ReentrantLock sReentrantLock = new ReentrantLock(); private static Condition sSuspendCondition = sReentrantLock.newCondition(); public static void main(String[] args) { /*NotInterruptThread mNotInterruptThread = new NotInterruptThread(); mNotInterruptThread.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } mNotInterruptThread.interrupt(); */ InterruptThread interruptThread = new InterruptThread(); interruptThread.start(); try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } interruptThread.interrupt(); /*InterruptThread1 interruptThread1 = new InterruptThread1(); interruptThread1.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } interruptThread1.interrupt();*/ /*InterruptThread2 interruptThread2 = new InterruptThread2(); interruptThread2.start(); try { Thread.sleep(3000); } catch (InterruptedException e1) { e1.printStackTrace(); } interruptThread2.interrupt();*/ /*sReentrantLock.lock(); try { sSuspendCondition.signal(); } catch (Exception e) { e.printStackTrace(); } finally { sReentrantLock.unlock(); }*/ } static class NotInterruptThread extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("=============NotInterruptThread execute... ============="); } } } static class InterruptThread extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("=============InterruptThread execute... ============="); try { Thread.sleep(50000); } catch (InterruptedException e) { e.printStackTrace(); break; } } } } static class InterruptThread1 extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { synchronized (sLock) { System.out.println("=============InterruptThread execute... ============="); try { sLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); break; } } } } } static class InterruptThread2 extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { sReentrantLock.lock(); try { System.out.println("=============InterruptThread execute... ============="); sSuspendCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); break; } finally { sReentrantLock.unlock(); } } } } }
我这里分别演示了使用sleep()、wait()、await()的方式来阻塞线程,然后在主线程休眠一段时间后尝试去中断,子线程中收到异常后调用break退出循环,实际试验都可以正常退出循环。
参考链接:
1. interrupt、interrupted 、isInterrupted 区别
3. 为什么说volatile+interrupt是停止线程最优雅的姿势?