在Java中有以下3种方式终止正在运行的线程:

  • 使用退出标志,使线程正常退出;
  • 使用stop()方法强行终止线程,不推荐使用该方法,JDK已声明弃用;
  • 使用interrupt方法中断线程。

使用标志位

在 run() 方法执行完毕后,该线程就终止了。但是在某些特殊的情况下,run() 方法会被一直执行;比如在服务端程序中可能会使用 while(true) { … } 这样的循环结构来不断的接收来自客户端的请求。此时就可以用修改标志位的方式来结束 run() 方法。

public class ServerThread extends Thread {//volatile修饰符用来保证其它线程读取的总是该变量的最新的值public volatile boolean exit = false; @Overridepublic 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; //修改标志位,退出线程}
}

使用stop()

通过查看 JDK 的 API,我们会看到 java.lang.Thread 类型提供了一系列的方法如 start()、stop()、resume()、suspend()、destory()等方法来管理线程。但是除了 start() 之外,其它几个方法都被声名为已过时(deprecated)。

虽然 stop() 方法确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且该方法已被弃用,最好不要使用它。

为什么弃用stop:

  • 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
  • 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。

例如,存在一个对象 u 持有 ID 和 NAME 两个字段,假如写入线程在写对象的过程中,只完成了对 ID 的赋值,但没来得及为 NAME 赋值,就被 stop() 导致锁被释放,那么当读取线程得到锁之后再去读取对象 u 的 ID 和 Name 时,就会出现数据不一致的问题,如下图:

使用 interrupt()

现在我们知道了使用 stop() 方式停止线程是非常不安全的方式,那么我们应该使用什么方法来停止线程呢?答案就是使用 interrupt() 方法来中断线程。

需要明确的一点的是:interrupt() 方法并不像在 for 循环语句中使用 break 语句那样干脆,马上就停止循环。调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程。

也就是说,线程中断并不会立即终止线程,而是通知目标线程,有人希望你终止。至于目标线程收到通知后会如何处理,则完全由目标线程自行决定。这一点很重要,如果中断后,线程立即无条件退出,那么我们又会遇到 stop() 方法的老问题。

事实上,如果一个线程不能被 interrupt,那么 stop 方法也不会起作用。

我们来看一个使用 interrupt() 的例子:

public class InterruptThread1 extends Thread{public static void main(String[] args) {try {InterruptThread1 t = new InterruptThread1();t.start();Thread.sleep(200);t.interrupt();} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void run() {super.run();for(int i = 0; i <= 200000; i++) {System.out.println("i=" + i);}}
}

输出:

从输出的结果我们会发现 interrupt 方法并没有停止线程 t 中的处理逻辑,也就是说即使 t 线程被设置为了中断状态,但是这个中断并不会起作用,那么该如何停止线程呢?

这就需要使用到另外两个与线程中断有关的方法了:

public boolean Thread.isInterrupted() //判断是否被中断
public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态

这两个方法使得当前线程能够感知到是否被中断了(通过检查标志位)。

所以如果希望线程 t 在中断后停止,就必须先判断是否被中断,并为它增加相应的中断处理代码:

@Override
public void run() {super.run();for(int i = 0; i <= 200000; i++) {//判断是否被中断if(Thread.currentThread().isInterrupted()){//处理中断逻辑break;}System.out.println("i=" + i);}
}

输出结果,for 循环在执行完成前就提前结束了:

在上面这段代码中,我们增加了 Thread.isInterrupted() 来判断当前线程是否被中断了,如果是,则退出 for 循环,结束线程。

这种方式看起来与之前介绍的“使用标志位终止线程”非常类似,但是在遇到 sleep() 或者 wait() 这样的操作,我们只能通过中断来处理了。

public static native void sleep(long millis) throws InterruptedException

Thread.sleep() 方法会抛出一个 InterruptedException 异常,当线程被 sleep() 休眠时,如果被中断,这会就抛出这个异常。
(注意:Thread.sleep() 方法由于中断而抛出的异常,是会清除中断标记的。)

Java停止线程的3种方式相关推荐

  1. java怎样输入五个数字打一成语,Java的线程安全四种方式五个等级[1]

    Java的线程安全四种方式五个等级[1]以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 四种方式 sychronized ...

  2. java 创建线程_【80期】说出Java创建线程的三种方式及对比

    点击上方"Java面试题精选",关注公众号 面试刷图,查缺补漏 >>号外:往期面试题,10篇为一个单位归置到本公众号菜单栏->面试题,有需要的欢迎翻阅. 一.Ja ...

  3. Java创建线程的三种方式

    一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实 ...

  4. Java多线程 - Java创建线程的4种方式

    文章目录 1. Java创建线程有哪几种方式? 1.1 线程创建方法一:继承Thread类创建线程类 1.2 线程创建方法二:实现Runnable接口创建线程目标类 1.5 线程创建方法三:使用Cal ...

  5. java创建线程的两种方式及区别

    本文将介绍创建线程的两种方式,示例代码在下面,复制粘贴即可 继承Thread类方式和实现Runnable接口方式 区别:由于在开发的过程中,很多的类都会用到继承的方式,如果采用继承的方式会让各个类之间 ...

  6. Java终止线程的三种方式

    停止一个线程通常意味着在线程处理任务完成之前停掉正在做的操作,也就是放弃当前的操作. 在 Java 中有以下 3 种方法可以终止正在运行的线程: 使用退出标志,使线程正常退出,也就是当 run() 方 ...

  7. Java创建线程的三种方式,以前只知道两种,现在添加一种Callable与FutureTask创建的方式

    一共有以下三种方式: 1.继承Thread 2.实现Runnable 3.实现Callable,并FutureTask包装 线程启动方式均是使用start()方法 先阐述优缺点: 1和2,3: 2,3 ...

  8. Java 创建线程的三种方式

    一.继承Thread类创建 1.定义一个类继承Thread类,并重写Thread类的run()方法,run()方法的方法体就是线程要完成的任务,因此把run()称为线程的执行体: 2.创建该类的实例对 ...

  9. java创建线程池几种方式_java知识总结-创建线程池的6种方式

    一.创建线程池的6种方式: Executors.newCachedThreadPool(); 创建一个可缓存线程池,应用中存在的线程数可以无限大 Executors.newFixedThreadPoo ...

最新文章

  1. 超越Google,快手落地业界首个万亿参数推荐精排模型
  2. UI自动化测试中的页面定位问题,年薪50W软件测试工程师为你解答
  3. C#使用BackgroundWorker实现多线程
  4. Modelsim command line 传参数到 .do 文件
  5. java连接mongodb的jar包_Java实战之管家婆记账系统(1)——项目简述
  6. 深入理解计算机系统----读书笔记
  7. [react] React根据不同的环境打包不同的域名?
  8. raspberry pi_如何使用Raspberry Pi构建WiFi相框
  9. 字符串分割函数strtok_r的用法
  10. android fragment面试,Android fragment之间传递数据的方式?
  11. mysql中各种连接的区别
  12. 2012-11-26 → 2012-12-02 周总结:项目又有新需求了,很兴奋
  13. 图片不能有透明通道AppStore images can't contain alpha channels or transparencies windows iOS
  14. POST 和GET传输的最大容量分别是多少?
  15. qml实现雪花飘落,快来给你的暑假降降温吧
  16. button组件 untiy_Unity 3D Button控件
  17. Selenium +Python项目实践(注册流程)
  18. linux系统开启端口命令
  19. 三相异步电机----电机公式(三)
  20. erp系统实施方案会遇到哪些问题?

热门文章

  1. 数据结构------最短路径(Dijkstra)算法(爆肝详解)
  2. PLC中ST编程的基础知识
  3. plsqldev与sqldeveloper
  4. MySql 授权用户权限如何设置?
  5. RSA2048签名和加密+OAEP填充方式(前端)
  6. 自动化之RPA工具之UiBot
  7. Amazon EKS 上有状态服务启用存储加密
  8. julia编程语言有前途吗?
  9. 那些年CUDA编程那些事(一)
  10. 济南python工资一般多少-济南在线学Python