终止线程一般建议采用的方法是让线程自行结束,进入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循环中执行。

 package com.test01.stopThread;

 class MyThread extends Thread {
private volatile boolean exit = false; // volatile保证exit的同步 public void exit(){
exit = true; // 标记位
} @Override
public void run() {
while (!exit){ // 通过标记位控制while循环中的任务
System.out.println("This is a thread.");
}
}
} public class ThreadFlag {
public static void main(String [] args) throws Exception{
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.start(); // 启动线程thread1
thread2.start(); // 启动线程thread2
Thread.sleep(1000); // 当前线程睡眠5秒钟
thread1.exit(); // 终止thread1
thread2.exit(); // 终止thread2
thread1.join(); // 当前线程等待thread1执行完
thread2.join(); // 当前线程等待thread2执行完
System.out.println(" Thread had been exited");
}
}

第三种 使用 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()来退出线程的最好的方式应该是两种情况都要考虑。

阻塞时抛出异常的情景

  package com.test01.stopThread;

  class MyThread01 extends Thread{
@Override
public void run(){
try {
sleep(50000); // sleep()是Thread类的静态方法
System.out.println("线程正在执行。");
} catch (InterruptedException e){ // 阻塞时sleep()方法会抛出异常
System.out.println("线程终止。");
System.out.println(e.getMessage());
break; // 捕获异常之后,退出循环
}
}
} public class Interrupt1 {
public static void main(String [] args)throws Exception {
MyThread01 thread01 = new MyThread01();
thread01.start();
System.out.println("在50秒内按任意键终止线程");
System.in.read();
thread01.interrupt(); // 中断线程thread01
thread01.join(); // 当前线程等待thread01执行完
System.out.println("线程已经结束");
}
}

非阻塞不抛出异常的情景

 package com.test01.stopThread;

 class MyThread01 extends Thread{
@Override
public void run(){
while(!isInterrupted()){ // 可以替换成Thread.interrupted()
System.out.println("线程执行中");
}
}
} public class Interrupt1 {
public static void main(String [] args)throws Exception {
MyThread01 thread01 = new MyThread01();
thread01.start();
Thread.sleep(10);
thread01.interrupt(); // 中断线程thread01
thread01.join(); // 当前线程等待thread01执行完
System.out.println("线程已经结束");
}
}

注意:在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. ajax请求是参数问题

    Illegal invocation processData:false,processData用于对data参数进行序列化处理,默认值是true.默认情况下发送的数据将被转换为对象,如果不希望把Fi ...

  2. 2018面向对象程序设计(Java)第15周学习指导及要求

    2018面向对象程序设计(Java)第15周学习指导及要求 (2018.12.6-2018.12.9)   学习目标 (1) 掌握Java应用程序打包操作: (2) 了解应用程序存储配置信息的两种方法 ...

  3. 3D 模型

    http://www.imooc.com/article/12670

  4. mybatis 插入返回自增后的id

    //serviceImpl int customerId = customerDao.insertDynamic(customer1); System.out.println("id==== ...

  5. JSF web.xml的各类参数属性配置

    出处:http://www.cnblogs.com/zxpgo/articles/2570175.html 感谢作者的分享!! ———————————————————————————————————— ...

  6. spark快速开发之scala基础之3类,对象,特征

    类 scala的类定义非常灵活 class test4 class test2{} class test3(x:Int) 定义一个带构造函数的类 class Point (x : Int,y : In ...

  7. java面试技巧

    简历 1.HR看简历,都是看技术关键词.可以多看招聘要求,简历上要多写些关键词.比如io,集合,多线程,并发,spring,mysql,分布式等等. 2.可以准备多份简历,根据不同的jd发送不同的简历 ...

  8. 全国高校绿色计算大赛 预赛第一阶段(C++)第3关:旋转数组

    挑战任务 在计算机中,一张数字图像,可以被看做是一个矩阵或者说数组. 学过线性代数的同学对矩阵肯定不陌生.一般来说,图像是一个标准的矩形,有着宽度(width)和高度(height).而矩阵有着行(r ...

  9. 如何解决make: Nothing to be done for `all' 的方法

    正常情况下,当文件没有更新且已经编译过时,再次make就会报这个错误,表示文件未更新,不需要编译. 如果异常情况没有检测到更新文件,或者想要强制重新编译,只需要make clean,再次编译即可.

  10. fullCalendar插件基本使用

    效果图 html代码,需要引入jquery,layui,fullCalendar <!DOCTYPE html> <html lang="en"> < ...