Java 多线程 --- 终止线程 Terminate Threads

2023-11-07

为什么要终止线程

  • 线程消耗资源(包括内存,内核, CPU等资源).
  • 只有当一个Java程序的所有线程都运行结束的时候,一个 Java 程序才算运行结束.
  • 所以当一个线程不再被需要使用时或者运行不正常时需要清理掉.
  • 下面代码中, 即使main方法已经运行完毕, 但是整个程序还是等待 BlockingTask运行结束.
public class Main1 {
    public static void main(String [] args) {
        Thread thread = new Thread(new BlockingTask());

        thread.start();
    }

    private static class BlockingTask implements Runnable {

        @Override
        public void run() {
            //do things
            try {
                Thread.sleep(500000);
            } catch (InterruptedException e) {
                System.out.println("Existing blocking thread");
            }
        }
    }
}

终止线程的方法

return()

  • 当一个线程的run方法执行return语句时, 线程会自动结束

stop()

  • 再以前的版本中, 使用stop和suspend可以立即结束一个线程
  • 但是已经被废弃, 因为直接中断的方式,并没有让线程留下存储数据的时间,这也极容易导致线程的数据丢失或不一致性的问题

interrupt()

  • java并没有提供任何机制来安全的停止线程,只提供了中断(interruption),这其实是一种协作机制,让一个线程去通知另外一个线程停止当前的工作。
  • interrupt方法不是直接终止线程, 而是给目标线程发送一个中断信号,如果目标线程没有接收线程中断的信号并结束线程,线程则不会终止,具体是否退出或者执行其他逻辑由目标线程决定.
  • When the interrupt method is called on a thread, the interrupted status of the thread is set. This is a boolean flag that is present in every thread.

interrupt() 和 isInterrupted()

  • 可以使用interrupt()isInterrupted()从一个线程中断另一个线程并查看目前线程是否被中断
import java.math.BigInteger;
public class Main2 {

    public static void main(String[] args) {
        Thread thread = new Thread(new LongComputationTask(new BigInteger("200000"), new BigInteger("100000000")));

        thread.start();
        //中断thread线程
        thread.interrupt();
    }

    private static class LongComputationTask implements Runnable {
        private BigInteger base;
        private BigInteger power;

        public LongComputationTask(BigInteger base, BigInteger power) {
            this.base = base;
            this.power = power;
        }

        @Override
        public void run() {
            System.out.println(base + "^" + power + " = " + pow(base, power));
        }

        private BigInteger pow(BigInteger base, BigInteger power) {
            BigInteger result = BigInteger.ONE;

            for (BigInteger i = BigInteger.ZERO; i.compareTo(power) != 0; i = i.add(BigInteger.ONE)) {
                
                // 查看目前线程是否被中断, 以及做出相应处理
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("Prematurely interrupted computation");
                    return BigInteger.ZERO;
                }
                result = result.multiply(base);
            }

            return result;
        }
    }
}

InterruptedException

  • 当线程处于阻塞状态时(比如sleep和wait), 线程无法使用isInterrupted()查看是否收到中断信号, 此时需要InterruptedException
  • InterruptedException会结束线程的阻塞状态
Runnable r = () -> {
 try
 {
 	 . . .
	 while (more work to do)
	 {
		//do more work
	 	Thread.sleep(delay);
	 }
 }
 catch(InterruptedException e) {
 	// thread was interrupted during sleep
 }
 finally {
	//cleanup, if required
 }
 // exiting the run method terminates the thread
};
  • 当InterruptedException被抛出后, Interrupt status会被清除
  • 下面代码就中断失败, 因为当InterruptedException被抛出后, Interrupt status被清除. 代码进入不到if语句
private static void test3() throws InterruptedException {
    Thread thread = new Thread(() -> {
        while (true) {
            // 响应中断
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("青秧线程被中断,程序退出。");
                return;
            }

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.out.println("青秧线程休眠被中断,程序退出。");
            }
        }
    });
    thread.start();
    Thread.sleep(2000);
    thread.interrupt();
}
  • 中断成功: 在catch中加入Thread.currentThread().interrupt(). 重新设置中断状态.
private static void test4() throws InterruptedException {
    Thread thread = new Thread(() -> {
        while (true) {
            // 响应中断
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("青秧线程被中断,程序退出。");
                return;
            }

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.out.println("青秧线程休眠被中断,程序退出。");
                Thread.currentThread().interrupt();
            }
        }
    });
    thread.start();
    Thread.sleep(2000);
    thread.interrupt();
}

使用sleep时, 不要在底层代码中处理InterruptException

public class PassInterrupt implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("go");
            throwInMethod();
        }
    }
    private void throwInMethod()  {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread (new PassInterrupt());
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }
}

在这里插入图片描述

  • 因为throwInMethod存在于底层方法中,如果在其中进行try/catch顶层方法可能无法感知,导致该中断被遗漏.

正确方式: 将exception抛给顶层方法处理

public class PassInterrupt implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("go");
            try {
                throwInMethod();
            } catch (InterruptedException e) {
                //保存日志/停止程序等操作
                System.out.println("日志已经保存");
                e.printStackTrace();
            }
        }
    }
    private void throwInMethod() throws InterruptedException {
         Thread.sleep(2000);
        //不在这里try/catch 是因为在这里的代码层次很深,run在较高层次,而throwInMethod较低层次
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread (new PassInterrupt());
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }
}

isInterrupt() 和 interrupted的区别 (注意是interrupted不是interrupt)

  • The interrupted method is a static method that checks whether the current thread has
    been interrupted. Furthermore, calling the interrupted method clears the interrupted
    status of the thread.
  • isInterrupted method is an instance method that you can use to check whether any thread has been interrupted.
    Calling it does not change the interrupted status.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 多线程 --- 终止线程 Terminate Threads 的相关文章

随机推荐

  • 【ag-grid-vue】基本使用

    ag grid是一款功能和性能强大外观漂亮的表格插件 ag grid几乎能满足你对数据表格所有需求 固定列 拖动列大小和位置 多表头 自定义排序等等各种常用又必不可少功能 关于收费的问题 绝大部分应用用免费的社区版就够了 ag grid c
  • this.$msgbox创建弹窗,提示文字绑定事件-element ui + vue项目

    setDiloag const h this createElement var that this 注意 this msgbox title 提示 message h p null h span null 申请已提交成功 您可以在 on
  • 机器学习第八课--决策树

    举个例子 明天如果下雨我就不出门了 在这里我们用了一个决策条件 是否下雨 然后基于这个条件会有不同的结果 出门和不出门 这就是一个经典的决策树 决策树的核心组成部分 节点 边 最后的结论就是第一个决策树要优于第二个决策树 因为它的准确率更高
  • openGL之API学习(七十)windows的opengl扩展wgl

    WGL扩展说白了是Windows操作系统和OpenGL做交互的一系列扩展 glut也好 其他框架也好 都是对这些接口进行了封装 之前的文章也提到了 Windows在对OpenGL的原生支持非常不友好 甚至差点就夭折了 在wingdi h这个
  • CSRF攻击原理及防护

    CSRF攻击原理及防护 0x01 CSRF是什么 ssrf 服务端请求伪造 CSRF全称为跨站请求伪造 Cross site request forgery 是一种网络攻击方式 也被称为 one click attack 或者 sessio
  • Robot Framework 基于图像识别的 C/S 自动化测试 --- 从入门到实战

    目录 引子 雏形 库的选择 实施过程 1 导入并改造ImageHorizonLibrary 使其支持中文路径和中文名称 2 基于目录结构的Page Object封装 3 通过传统手段选获取页面文字内容的方法 1 通过鼠标三击获取字符串内容
  • Qt实现多选文件夹对话框

    简述 Qt使用QFileDialog类可以实现文件选择对话框 多文件选择对话框 以及文件夹选择对话框 就是没有多文件夹选择对话框 做的并不是很完美无法直接调用win下的原生对话框 下面将介绍一下Qt实现多选文件夹对话框的两种方式 目录 使用
  • Web项目之网络爬虫

    一 爬虫基础篇 Python网络爬虫 认识爬虫 Python网络爬虫 http和https协议 Python网络爬虫 基于urllib库的get请求页面 Python网络爬虫 requests模块应用1 Python网络爬虫 验证码处理 P
  • 水下图像——不平衡衰减相关文献阅读

    目录 不平衡衰减 相关文献 1 Underwater Single Image Color Restoration Using Haze Lines and a New Quantitative Dataset 1 2 Underwater
  • 电感怎么掌握?读懂本文就够了

    一提到电感 不少做设计的同事就发憷 因为不知道电感要怎么用选 很多时候 就像薛定谔的猫一样 只有打开了盒子 才知道猫是不是死的 只有电感实际在电路中焊上去 用起来了 才知道用的对不对 用的好不好 为什么电感这么难搞 因为电感涉及到电磁场 而
  • Web项目中获取SpringBean——在非Spring组件中获取SpringBean

    自定义一个工具类 实现自ApplicationContextAware接口 接口的方法是setApplicationContext 我们实现它 并让其为我们服务 因为Spring在load自己的时候会将上下文环境填充进来 我们所要做的就是将
  • 微服务体系下如何快速构建一个服务

    近两三年的时间 微服务是热度陡增 作为旧有SOA体系的一下特殊展现 在企业级应用市场上面应用越来越广泛 越来越多的团队 开始采用微服务架构来改造现有的架构体系 不管实施的情况如何 至少已经有成形的案例在线上跑 哪我们这些远未达到微服务架构的
  • 谷粒商城详细笔记

    前言 mysql安装在腾讯云 redis安装在本地虚拟机master上 运行时 renren fast这个项目要到单独开个idea窗口打开 一 项目简介 1 项目微服务架构图 微服务 拒绝大型单体应用 基于业务边界进行服务微化拆分 各个服务
  • 浏览器如何使用断点调试?

    在浏览器中按下F12进入开发者模式 点击Sources gt 选中相应的html文件 gt 在对应的代码行前点击 出现小红点 断点 再次运行 在执行到断点时就会停下 等待按下F9 F12才会向下执行 F11执行下一步 F9 返回上一步 将鼠
  • python3安装Pillow(PIL)

    本方法亲测可用 我的是win7 32位 Python3 4 官网上还没有支持Python3的PIL 使用Pillow代替PIL 首先 下载对应的whl文件 来源http www lfd uci edu gohlke pythonlibs 4
  • n个数分为两组,两组数的个数尽可能相等,差值最小

    题目描述 对于有n个数的数组 分为两组 这两组的数的个数尽可能相等 不超过1 同时两组的数之和的差值最小 这个题目使用类似0 1背包问题 思路 从k个数中选i个数 求所有可能的和 并把这些和放在flag中用true表示 k i flag见代
  • ubuntu忘记root密码怎么办?

    普通用户 无论你是否申请了root帐号 或是普通账号密码忘记了都没有问题的 首先 重启ubuntu 随即长按shift进入grub菜单 其次 选择第二个高级模式recovery mode进入Recovery Menu界面 选择root Dr
  • jsp代码中EL表达式无法显示(已解决)

    jstl最近是不是有问题 还是我的代码有问题 每次遍历都不会出来 都是显示这样 有的说是必须要有jstl jar和 standard jar 但是我也有了 但是也是没有说打刀口上 其实是忽略了一个知识点 EL表达式 在这里加上 isELIg
  • CUnit 单元测试 方法总结

    CUnit是一个用C语言编写 管理和运行单元测试的轻量级系统 它为C程序员提供了基本的测试功能和灵活的各种用户接口 CUnit被构建为一个与用户的测试代码链接的静态库 它使用一个简单的框架来构建测试结构 并为测试常见数据类型提供了一套丰富的
  • Java 多线程 --- 终止线程 Terminate Threads

    Java 多线程 终止线程 Terminate Threads 为什么要终止线程 终止线程的方法 return stop interrupt InterruptedException 为什么要终止线程 线程消耗资源 包括内存 内核 CPU等