为什么废弃Thread的stop函数?

简单来说就是stop方法中断线程太过暴力随意,且会是否线程持有的锁,会导致线程安全问题。还有可能导致存在需要被释放的资源得不到释放,引发内存泄露。所以用stop停止线程是不推荐的。

  1. stop是通过立即抛出ThreadDeath异常,来达到停止线程的目的,此异常抛出有可能发生在任何一时间点,包括在catch、finally等语句块中,但是此异常并不会引起程序退出。
  2. 由于有异常抛出,导致线程会释放全部所持有的锁,极可能引起线程安全问题。
  3. 有可能导致存在需要被释放的资源得不到释放,引发内存泄露。

使用Thread的interrupt()方法结束线程

调用Thread对象的interrupt函数并不是立即中断线程,只是将线程中断状态标志设置为true,当线程运行中有调用其阻塞的函数(Thread.sleep,Object.wait,Thread.join等时,像Thread.sleep()方法调用之后,会不断地轮询检测中断状态标志是否为true,如果为true,则停止阻塞并抛出InterruptedException异常,同时还会重置中断状态标志false;如果为false,我们在catch方法体里没有重新interrupt()把在中断状态标志设置为true的话,就会导致循环体无需循环下去,可参考下面的代码。

注意事项:

  • 使用isInterrupted来判断线程是否处于中断状态,若是中断状态,则跳出正在执行的任务,使线程结束运行。
  • 调用sleep()方法触发InterruptedException异常时,在catch代码块中需再次调用interrupt()方法,使线程再次处于中断状态,使while循环条件为false,使线程跳出循环,结束运行。若不调用,while循环为死循环,线程无法结束。

代码示例

public class InterruptTest {

    /**
* 结束未使用阻塞函数的线程
* @throws InterruptedException
*/
@Test
public void test1() throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("开始搬砖!");
//只要代码里没有异常,那么我们可以通过判断线程是否中断来执行业务操作
//当其他线程发出线程中断信号后就会跳出正在执行的任务,往下执行使线程结束运行。
while (!Thread.currentThread().isInterrupted()) {
System.out.println("西西弗斯的陷阱:无脑循环,日复一日搬砖!");
}
System.out.println("神迹出现,结束搬砖!");
System.out.println(Thread.currentThread().isInterrupted());//true
});
thread.start();
TimeUnit.MILLISECONDS.sleep(10);
System.out.println("启动超级进化形态!");
thread.interrupt();
}
/**
* 开始搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 。。。。。
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 启动超级进化形态!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 神迹出现,结束搬砖!
*/ /**
* 结束使用阻塞函数的线程
* @throws InterruptedException
*/
@Test
public void test2() throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("开始搬砖!");
//只要代码里没有异常,那么我们可以通过判断线程是否中断来执行业务操作
//当其他线程发出线程中断信号后就会跳出正在执行的任务,往下执行使线程结束运行。
while (!Thread.currentThread().isInterrupted()) {
System.out.println("西西弗斯的陷阱:无脑循环,日复一日搬砖!");
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().isInterrupted());//false
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().isInterrupted());//true
}
}
System.out.println("神迹出现,结束搬砖!");
});
thread.start();
TimeUnit.MILLISECONDS.sleep(1000);
System.out.println("启动超级进化形态!");
thread.interrupt();
//主线程加上这个睡眠时间是为了便于查看当没有在catch代码块中需调用interrupt函数,使线程再次处于中断状态,
// 使while循环条件为false,使线程跳出循环,结束运行。若不调用,while循环为死循环,线程无法结束。
TimeUnit.SECONDS.sleep(3000);
}
/**
* catch中有调用 Thread.currentThread().interrupt();
* 开始搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 启动超级进化形态!
* java.lang.InterruptedException: sleep interrupted
* at java.lang.Thread.sleep(Native Method)
* at java.lang.Thread.sleep(Thread.java:340)
* at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
* at cn.vv.schedule.module.rewardpunishment.service.InterruptTest.lambda$test2$1(InterruptTest.java:64)
* at java.lang.Thread.run(Thread.java:748)
* 神迹出现,结束搬砖!
*/ /**
* catch中没有调用 Thread.currentThread().interrupt();线程会无需循环下去,直到主线程结束
*开始搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 启动超级进化形态!
* java.lang.InterruptedException: sleep interrupted
* at java.lang.Thread.sleep(Native Method)
* at java.lang.Thread.sleep(Thread.java:340)
* at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
* at cn.vv.schedule.module.rewardpunishment.service.InterruptTest.lambda$test2$1(InterruptTest.java:64)
* at java.lang.Thread.run(Thread.java:748)
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 西西弗斯的陷阱:无脑循环,日复一日搬砖!
* 。。。。。。一直下去
*/ }

Thread的静态函数interrupted与Thread的对象函数isInterrupted比较

静态方法Thread.interrupted()会在检测线程中断状态标志是否为true后,还会将中断状态标志重置为false

对象方法thread.isInterrupted()只是检测线程中断状态标志

//静态方法
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
//对象方法
public boolean isInterrupted() {
return isInterrupted(false);
} /**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
//ClearInterrupted表示是否清除中断标示状态,清除后为false
private native boolean isInterrupted(boolean ClearInterrupted);

参考

Java线程中断的理解和正确使用

如何优雅正确地通过interrupt方法中断线程的更多相关文章

  1. Thread中断线程的方法

    转载:https://www.cnblogs.com/l2rf/p/5566895.html 线程对象属于一次性消耗品,一般线程执行完run方法之后,线程就正常结束了,线程结束之后就报废了,不能再次s ...

  2. 中断线程详解(Interrupt)

    在上篇文章<多线程的使用——Thread类和Runnable接口>中提到中断线程的问题.在JAVA中,曾经使用stop方法来停止线程,然而,该方法具有固有的不安全性,因而已经被抛弃(Dep ...

  3. Thread的中断机制(interrupt),循环线程停止的方法

    一.中断原理 中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个 ...

  4. java 中断线程的几种方式 interrupt()

    中断 中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作.线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个程序.虽然初次看来它可能显 ...

  5. 廖雪峰Java11多线程编程-1线程的概念-5中断线程

    1.中断线程: 如果线程需要执行一个长时间任务,就可能需要中断线程.场景:从网络上下载一个100M的文件,用户在下载过程中中断下载任务的执行. 中断线程就是其他线程给该线程发一个信号,该线程收到信号后 ...

  6. Java 并发 中断线程

    Java 并发 中断线程 @author ixenos 对Runnable.run()方法的三种处置情况 1.在Runnable.run()方法的中间中断它 2.等待该方法到达对cancel标志的测试 ...

  7. java并发编程(一)线程状态 & 线程中断 & 线程间的协作

    参考文章: Java线程的5种状态及切换:http://blog.csdn.net/pange1991/article/details/53860651 线程的5种状态: 1. 新建(NEW):新创建 ...

  8. java线程基础巩固---Thread中断Interrupt方法学习&采用优雅的方式结束线程生命周期

    Interrupt学习: 在jdk中关于interrupt相关方法有三个,如下: 关于上面的疑问会在稍后进行阐述滴,下面看代码: 编译运行: 应该说是t线程为啥在被打断之后没有退出,还是在运行状态,这 ...

  9. 注意Thread.interrupt()方法的真正作用并不是用来中断线程

      程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误.      在本篇文章中,我们针对这些难题之一:如何中断一个正在 ...

随机推荐

  1. 深入理解Spring IOC容器

    本文将从纯xml模式.xml和注解结合.纯注解的方式讲解Spring IOC容器的配置和相关应用. 纯XML模式 实例化Bean的三种方式: 使用无参构造函数 默认情况下,会使用反射调用无参构造函数来 ...

  2. 『与善仁』Appium基础 — 7、ADB Shell命令的使用

    目录 1.查看进程 2.查看实时资源占用情况 3.查看进程 UID 4.其它ADB Shell命令说明 Android系统是基于 Linux 内核的,也就是说Android系统的底层是Linux系统. ...

  3. Part 23 to 26 Routing in Angular

    Part 23 AngularJS routing tutorial In general, as the application becomes complex you will have more ...

  4. LINKERD 2.11 中文实战手册

    1. 将您的服务添加到 Linkerd. 为了让您的服务利用 Linkerd,它们还需要通过将 Linkerd 的数据平面代理注入到它们的 pod 中来进行 网格化 . 2. 自动化的金丝雀发布. 通 ...

  5. 『学了就忘』Linux软件包管理 — 47、Linux源码包的安装和卸载

    目录 1.源码包安装服务的注意事项 2.源码包安装服务的过程 3.源码包安装服务的删除 4.源码包安装服务的启动 5.源码包安装服务的关闭 1.源码包安装服务的注意事项 (1)安装服务选择哪种软件包? ...

  6. mybatis新增账号并且返回主键id

    <!--新增账号和权限的关联关系--><insert id="save" useGeneratedKeys="true" keyPropert ...

  7. Hi3516开发笔记(五):通过HiTools使用网口将uboot、kernel、roofts和userdata按照分区表烧写镜像

    前言   前面生成了uboot,kernel,sample,userdata(我们实际修改了ip的),rootfs,现在需要烧写进入核心板.   使用网口烧写镜像(海思烧写必须占用调试串口) 步骤一: ...

  8. Sentry 监控 - Snuba 数据中台本地开发环境配置实战

    系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps Sentry For ...

  9. Codeforces 1270H - Number of Components(线段树)

    Codeforces 题目传送门 & 洛谷题目传送门 首先需发现一个性质,那就是每一个连通块所对应的是一个区间.换句话说 \(\forall l<r\),若 \(l,r\) 在同一连通块 ...

  10. 洛谷 P6499 - [COCI2016-2017#2] Burza(状压 dp)

    题面传送门 一道挺有意思的思维题(?) 首先我们假设根节点深度为 \(0\),那么 Daniel 的目标显然就是堵住一些节点使得 Stjepan 不能移动到深度为 \(k\) 的节点,Stjepan ...