Java中终止线程的三种方法
终止线程一般建议采用的方法是让线程自行结束,进入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中终止线程的三种方法的更多相关文章
- java中终止线程的三种方式
在java中有三种方式可以终止线程.分别为: 1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止. 2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和sus ...
- JAVA中创建线程的三种方法及比较
JAVA中创建线程的方式有三种,各有优缺点,具体如下: 一.继承Thread类来创建线程 1.创建一个任务类,继承Thread线程类,因为Thread类已经实现了Runnable接口,然后重写run( ...
- Java中创建线程的三种方法以及区别
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.Java可以用三种方式来创建线程,如下所示: 1)继承Thread类创建线程 2)实现Runnable接口创建线 ...
- Java中创建线程的三种方式以及区别
在java中如果要创建线程的话,一般有3种方法: 继承Thread类: 实现Runnable接口: 使用Callable和Future创建线程. 1. 继承Thread类 继承Thread类的话,必须 ...
- java中创建线程的3种方法
1.继承Thread类优点:可以直接使用Thread类中的方法,代码比较简单.缺点:继承Thread类之后不能继承其他类. 2.实现Runable接口优点:实现接口,比影响继承其他类或实现接口.缺点: ...
- java中创建线程的几种方法及区别
1,实现Runnable接口创建线程 特点: A:将代码和数据分开,形成清晰的模型 B:线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法 C:有利于保持程序风格的一致性 2,继承Th ...
- Java中创建线程的三种方式及其优缺点
1.自定义一个继承Thread的类,由于Java的单继承特性,限制了该类的扩展性. 2.实现Runnable接口,重写run()方法. 3.实现Callable接口,重写call方法.线程执行体可以有 ...
- (转)Java结束线程的三种方法
背景:面试过程中问到结束线程的方法和线程池shutdown shutdownnow区别以及底层的实现,当时答的并不好. Java结束线程的三种方法 线程属于一次性消耗品,在执行完run()方法之后线程 ...
- Java结束线程的三种方法(爱奇艺面试)
线程属于一次性消耗品,在执行完run()方法之后线程便会正常结束了,线程结束后便会销毁,不能再次start,只能重新建立新的线程对象,但有时run()方法是永远不会结束的.例如在程序中使用线程进行So ...
随机推荐
- vue 父向子组件传递数据,子组件向父组件传递数据方式
父组件向子组件传递数据通过props,子组件引入到父组件中,设置一个值等于父组件的数据,通过:bind将数据传到子组件中,子组件中通过props接收父组件的数据,这样就可以使用父组件的数据了,循环组件 ...
- git库初次下载
1.右键Git Batch Here==>输入 git config --list 确认2.再次输入ssh-keygen -t rsa -C “修改后的邮箱” 3.回车多次 找到 生成序列目录 ...
- Python 继承与多继承
相关知识点: __class__.__name__的用法. >>> class ABC: def func(self): print('打印类名:',__class__.__name ...
- Pandas文本操作之读取操作
读写文本格式的数据 pandas中的解析函数 函数 说明 read_csv 从文件.url.文件型对象中加载带分隔符的数据,默认分隔符为逗号 read_table 从文件.url.文件型对象中加载带分 ...
- html中相对(relative),绝对(absolute)位置以及float的学习和使用案例 (转)
这几天着手于CSS的研究,研究的原因主要是工作需要,最近发现如果做前端仅仅会javascript很难尽善尽美,当然懂样式和html在一定程度上可以让我们更近一步. css较为简单,由于个人擅长编写代码 ...
- GitHub优秀项目
https://blog.csdn.net/javaxuexi123/article/details/79248124
- PHP20-challenge10
今天咩,说一个关于php的题目,里面主要主要牵扯到截断的知识点,这让我多了解了一些机制. 1.截断 截断,简单来说就是16进制的00,代表空.其实,那些输出语句函数就是凭借语句后面这个我们看不 ...
- P3375 【模板】KMP字符串匹配
P3375 [模板]KMP字符串匹配 https://www.luogu.org/problemnew/show/P3375 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在 ...
- 微信小程序开发之获取用户手机号码——使用简单php接口demo进行加密数据解密
后边要做一个微信小程序,并要能获取用户微信绑定的手机号码.而小程序开发文档上边提供的获取手机号码的接口(getPhoneNumber())返回的是密文,需要服务器端进行解密,但是官方提供的开发文档一如 ...
- 【python】理解循环:for,while
先看下for结构: #!/usr/bin/python # -*- Coding:UTF-8 -*- for i in range(1): print i 输出: 0 输入和输出: #!/usr/bi ...