终止线程一般建议采用的方法是让线程自行结束,进入Dead(死亡)状态,就是执行完run()方法。即如果想要停止一个线程的执行,就要提供某种方式让线程能够自动结束run()方法的执行。比如设置一个标志来控制循环是否执行,通过这种方式让线程离开run()方法。

第一种 使用Thread类提供的stop()方法或suspend()方法强制终止线程(不安全,不要用)

第二种 使用volatile标记位退出线程

第三种 使用 interrupt()方法终止线程

由于其他原因导致线程停滞(如 I/O),进入非运行状态,停止线程的基本思路也是触发一个异常,而这个异常与导致线程停滞的原因相关。


第一种 使用Tread类提供的stop()方法或suspend()方法强制终止线程(不安全,不要用)

在当前线程中使用Thread类提供的stop()方法来终止其它线程,它会释放已经锁定的所有监视资源。如果当前任何一个受到这些监视资源保护的对象处于一个不一致的状态,其他的线程将会看到这个不一致的状态,这可能会导致程序执行的不确定性,且这种问题很难被定位。

在当前线程中使用Thread类提供的suspend()方法来挂起其它线程,然后使用resume()方法恢复。该方法容易引起死锁。线程在调用suspend()方法时不会释放锁,这就会导致一个问题:如果在当前线程中使用一个suspend()挂起一个持有锁的线程,如果当前线程也试图取得同样的对象锁,程序就会发生死锁。

鉴于以上两种方法的不安全性,Java语言已经不建议使用以上两种方法来终止线程。

第二种 使用volatile标记位退出线程

就是在现线程定义中设置一个boolean型的标记位,在线程的run()方法中根据这个标记位是true还是false来判断是否退出。这种情况一般是将任务放在run()方法中的一个while循环中执行。

  1. package com.test01.stopThread;
  2.  
  3. class MyThread extends Thread {
  4. private volatile boolean exit = false; // volatile保证exit的同步
  5.  
  6. public void exit(){
  7. exit = true; // 标记位
  8. }
  9.  
  10. @Override
  11. public void run() {
  12. while (!exit){ // 通过标记位控制while循环中的任务
  13. System.out.println("This is a thread.");
  14. }
  15. }
  16. }
  17.  
  18. public class ThreadFlag {
  19. public static void main(String [] args) throws Exception{
  20. MyThread thread1 = new MyThread();
  21. MyThread thread2 = new MyThread();
  22. thread1.start(); // 启动线程thread1
  23. thread2.start(); // 启动线程thread2
  24. Thread.sleep(1000); // 当前线程睡眠5秒钟
  25. thread1.exit(); // 终止thread1
  26. thread2.exit(); // 终止thread2
  27. thread1.join(); // 当前线程等待thread1执行完
  28. thread2.join(); // 当前线程等待thread2执行完
  29. System.out.println(" Thread had been exited");
  30. }
  31. }

第三种 使用 interrupt ()方法终止线程

使用interrupt()方法来终止来终止线程分为两种情况:

1)线程处于阻塞状态,如使用了sleep,同步锁的wait,socket中的receiver,accept等方法时,会使线程处于阻塞状态。当调用线程的interrupt()方法时,会抛出InterruptException异常。阻塞中的那个方法抛出这个异常,通过代码捕获该异常,然后break跳出循环状态,从而让我们有机会结束这个线程的执行。通常很多人认为只要调用interrupt方法线程就会结束,实际上是错的, 一定要先捕获InterruptedException异常之后通过break来跳出循环,才能正常结束run方法。

2)线程未处于阻塞状态,使用isInterrupted()判断线程的中断标志来退出循环。当使用interrupt()方法时,中断标志就会置true,和使用自定义的标志来控制循环是一样的道理。

为什么要区分进入阻塞状态和和非阻塞状态两种情况了,是因为当阻塞状态时,如果有interrupt()发生,系统除了会抛出InterruptedException异常外,还会调用interrupted()函数,调用时能获取到中断状态是true的状态,调用完之后会复位中断状态为false,所以异常抛出之后通过isInterrupted()是获取不到中断状态是true的状态,从而不能退出循环,因此在线程未进入阻塞的代码段时是可以通过isInterrupted()来判断中断是否发生来控制循环,在进入阻塞状态后要通过捕获异常来退出循环。因此使用interrupt()来退出线程的最好的方式应该是两种情况都要考虑。

阻塞时抛出异常的情景

  1. package com.test01.stopThread;
  2.  
  3. class MyThread01 extends Thread{
  4. @Override
  5. public void run(){
  6. try {
  7. sleep(50000); // sleep()是Thread类的静态方法
  8. System.out.println("线程正在执行。");
  9. } catch (InterruptedException e){ // 阻塞时sleep()方法会抛出异常
  10. System.out.println("线程终止。");
  11. System.out.println(e.getMessage());
  12. break // 捕获异常之后,退出循环
  13. }
  14. }
  15. }
  16.  
  17. public class Interrupt1 {
  18. public static void main(String [] args)throws Exception {
  19. MyThread01 thread01 = new MyThread01();
  20. thread01.start();
  21. System.out.println("在50秒内按任意键终止线程");
  22. System.in.read();
  23. thread01.interrupt(); // 中断线程thread01
  24. thread01.join(); // 当前线程等待thread01执行完
  25. System.out.println("线程已经结束");
  26. }
  27. }

非阻塞不抛出异常的情景

  1. package com.test01.stopThread;
  2.  
  3. class MyThread01 extends Thread{
  4. @Override
  5. public void run(){
  6. while(!isInterrupted()){ // 可以替换成Thread.interrupted()
  7. System.out.println("线程执行中");
  8. }
  9. }
  10. }
  11.  
  12. public class Interrupt1 {
  13. public static void main(String [] args)throws Exception {
  14. MyThread01 thread01 = new MyThread01();
  15. thread01.start();
  16. Thread.sleep(10);
  17. thread01.interrupt(); // 中断线程thread01
  18. thread01.join(); // 当前线程等待thread01执行完
  19. System.out.println("线程已经结束");
  20. }
  21. }

注意:在Thread类中有两个方法可以判断线程是否被中断。

一个是Thread类的静态方法interrupted(),用来判断当前线程是否被中断。

一个是非静态方法isInterrupted(),判断调用这个方法的线程是否被中断,即可以在当前线程中判断其他线程是否被中断。

Java中终止线程的三种方法的更多相关文章

  1. java中终止线程的三种方式

    在java中有三种方式可以终止线程.分别为: 1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止.  2.  使用stop方法强行终止线程(这个方法不推荐使用,因为stop和sus ...

  2. JAVA中创建线程的三种方法及比较

    JAVA中创建线程的方式有三种,各有优缺点,具体如下: 一.继承Thread类来创建线程 1.创建一个任务类,继承Thread线程类,因为Thread类已经实现了Runnable接口,然后重写run( ...

  3. Java中创建线程的三种方法以及区别

    Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.Java可以用三种方式来创建线程,如下所示: 1)继承Thread类创建线程 2)实现Runnable接口创建线 ...

  4. Java中创建线程的三种方式以及区别

    在java中如果要创建线程的话,一般有3种方法: 继承Thread类: 实现Runnable接口: 使用Callable和Future创建线程. 1. 继承Thread类 继承Thread类的话,必须 ...

  5. java中创建线程的3种方法

    1.继承Thread类优点:可以直接使用Thread类中的方法,代码比较简单.缺点:继承Thread类之后不能继承其他类. 2.实现Runable接口优点:实现接口,比影响继承其他类或实现接口.缺点: ...

  6. java中创建线程的几种方法及区别

    1,实现Runnable接口创建线程 特点: A:将代码和数据分开,形成清晰的模型 B:线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法 C:有利于保持程序风格的一致性 2,继承Th ...

  7. Java中创建线程的三种方式及其优缺点

    1.自定义一个继承Thread的类,由于Java的单继承特性,限制了该类的扩展性. 2.实现Runnable接口,重写run()方法. 3.实现Callable接口,重写call方法.线程执行体可以有 ...

  8. (转)Java结束线程的三种方法

    背景:面试过程中问到结束线程的方法和线程池shutdown shutdownnow区别以及底层的实现,当时答的并不好. Java结束线程的三种方法 线程属于一次性消耗品,在执行完run()方法之后线程 ...

  9. Java结束线程的三种方法(爱奇艺面试)

    线程属于一次性消耗品,在执行完run()方法之后线程便会正常结束了,线程结束后便会销毁,不能再次start,只能重新建立新的线程对象,但有时run()方法是永远不会结束的.例如在程序中使用线程进行So ...

随机推荐

  1. SSM框架简介及整合教程

    1.Spring Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (控制反转) 和 A面向切面编程).Spring框架是个轻量级的Java E ...

  2. Mysql5.6 导出sql文件数据导入到5.7

    由于在linux安装了mysql5.7,在需要导入数据时发现报错,说时间默认值不能为0,因为之前用的是mysql5.6 的版本.经过网上百度查找方法,发现是mysql的sql_mode值的问题,于是就 ...

  3. Win10 Fn键切换

    [Win10 Fn键切换] 选择 FN+ESC 参考:https://zhidao.baidu.com/question/626159613433698444.html

  4. easymock单元测试跟踪工具

    EasyMock can save a lot of legwork and make unit tests a lot faster to write. builder.com Java E-New ...

  5. pytest 学习笔记一:参数化与组织分层

    组织分层: 1.普通方式,和unittest分层类似: setup_module()  # 通常放在类外 setup_class(cls) setup(self) teardown(self) tea ...

  6. js保留小数点后面几位的方法

    原文地址: http://www.jb51.net/article/45884.htm 四舍五入以下处理结果会四舍五入: ? 1 2 var num =2.446242342; num = num.t ...

  7. apache 多并发测试

    进入到apache的bin目录打开  temp.bat 如果没有,新建temp.bat,打开输入 命令:ab -c 一次并发的数量 -n 总共请求的数量 请求的地址 例:ab -c 10 -n 100 ...

  8. NumPy 切片和索引

    NumPy 切片和索引 ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样. ndarray 数组可以基于 0 - n 的下标进行索引,切片对象可以 ...

  9. python之图像识别

    1. 安装配置 1.pip install pytesseract 2.pip install pillow 3.安装tesseract-ocr:http://jaist.dl.sourceforge ...

  10. python之栈和队列

    1. 栈 1.1 示例 #!/usr/bin/env python # -*- codinfg:utf-8 -*- ''' @author: Jeff LEE @file: .py @time: 20 ...