首页 > 编程语言 >阿里一面:Java中如何停止线程?

阿里一面:Java中如何停止线程?

时间:2024-03-14 09:56:11浏览次数:36  
标签:Java Thread 中断 任务 阿里 线程 停止 true

引言

在Java多线程编程中,正确且安全地停止线程是一项关键技能。简单粗暴地“杀死”线程不仅可能导致数据不一致性,还可能引发各种难以预测的错误。本文将探讨几种在Java中优雅地停止线程的方法,以确保程序的健壮性和可靠性。

使用标志位(共享变量)停止线程

一种常见的做法是使用一个boolean类型的标志位来控制线程的执行。线程在执行任务的过程中不断检查标志位的状态,当标志位被设置为true时,线程停止执行任务,从而退出线程。

class StoppableThread extends Thread {  
    private volatile boolean isStopped = true;  
  
    @Override  
    public void run() {  
        while (isStopped) {  
            // 线程执行任务的代码  
        }  
        // 清理资源并在检查到退出标志时退出  
    }  
  
    public void stopThread() {  
        // 在需要时设置标识=false,停止线程   
isStopped = false;  
    }  
}

这种方式简单易用,它可以控制线程的停止时机,灵活性较高,适用于简单的线程任务。但是如果任务执行时间过长或者任务中有阻塞操作,可能无法及时响应停止请求。并且这种方式的任务中需要周期性地检查标志位状态,可能会影响性能。

使用Thread.stop()方法(已过时)

虽然Thread类提供了stop()方法用于停止线程,但是这个方法已经被标记为过时(deprecated),不推荐使用。因为它可能会导致线程不安全的终止,引发一系列问题,如不释放锁、资源泄露等。

image.png

stop()方法确实可以停止线程的。

使用interrupt()方法

Java提供了一种基于中断模型的方式来请求线程停止。中断并不是立即停止线程的运行,而是设置一个中断标志,线程需要自行检查并响应这个中断信号。

public static void main(String[] args) {  
    // 默认情况下,interrupted标记位为false。该方法用于检查当前线程的中断状态,返回true表示线程已被中断,返回false表示线程未被中断  
    System.out.println("初始状态下的Interrupted标记位:" + Thread.currentThread().isInterrupted());  
    // 执行Interrupted。该方法用于中断当前线程,它会设置当前线程的中断标记位为true。  
    Thread.currentThread().interrupt();  
    System.out.println("执行Interrupted后的Interrupted标记位:" + Thread.currentThread().isInterrupted());  
    // 该方法用于检查当前线程的中断状态,并清除中断状态。如果当前线程被中断,则返回true,并清除中断状态;如果当前线程未被中断,则返回false。  
    System.out.println("返回当前线程:" + Thread.interrupted());  
    System.out.println(Thread.interrupted());  
}
初始状态下的Interrupted标记位:false
执行Interrupted后的Interrupted标记位:true
返回当前线程:true
false

在这段代码中,两次调用interrupted()方法,第一次返回true(因为之前调用了interrupt()方法),第二次返回false(因为在第一次调用后,中断状态被清除)。

Thread myThread = new Thread(() -> {  
    while (!Thread.currentThread().isInterrupted()) {  
        // 执行任务...  
    }  
    // 清理资源并在检查到中断标志时退出  
});  
  
myThread.start();  
// 在需要停止线程时  
myThread.interrupt();

对于阻塞操作(如IO操作或wait()方法),当线程在阻塞状态时收到中断请求,某些方法会抛出InterruptedException。在这种情况下,处理方式通常是捕获异常,执行必要的清理操作,并根据需要决定是否退出线程。

try {  
    synchronized (someLock) {  
        someLock.wait();  // 在wait期间,如果线程被中断,会抛出InterruptedException  
    }  
} catch (InterruptedException e) {  
    Thread.currentThread().interrupt(); // 重新设置中断标志,以便后续代码可以感知  
    // 清理并退出线程  
}

这种方式可以优雅地停止线程,即使线程处于阻塞状态也能够及时响应停止请求。通过捕获InterruptedException异常,可以在停止线程时进行清理工作。但是需要在线程任务中处理InterruptedException异常,这无形之中增加了代码复杂度。并且如果任务不是阻塞的,需要在任务中周期性地检查线程的中断状态。

使用线程池来管理线程

使用ExecutorService来管理线程可以更加灵活地控制线程的生命周期。通过调用ExecutorServiceshutdown()shutdownNow()方法来停止线程池中的所有线程,从而优雅地停止线程。

ExecutorService executor = Executors.newFixedThreadPool(5);  
  
// 提交任务到线程池  
executor.submit(new MyTask());  
  
// 关闭线程池  
executor.shutdown();

通过ExecutorService可以更加灵活地管理线程,包括启动、执行和停止。但是他是停止线程池中的所有线程。在Java中,没有直接提供停止线程池中特定线程的方法。因为线程池是一种管理线程的容器,它负责管理线程的创建、调度和销毁。但是我们可以使用Future对象来表示线程池中的任务,通过调用Futurecancel(boolean mayInterruptIfRunning)方法,可以尝试取消任务的执行。在调用cancel(true)时,表示可以中断正在运行的任务。

ExecutorService executor = Executors.newSingleThreadExecutor();  
Future<?> future = executor.submit(() -> {  
    // 执行任务...  
    // 在适当位置检查Thread.currentThread().isInterrupted()  
});  
  
// 在需要停止任务时  
future.cancel(true);  // 参数为true表示可以中断正在运行的任务  
executor.shutdown();

这种方式虽然调用了cancel(true),任务也需要在适当的时机检查中断状态并做出相应处理。如果任务已经被中断,可能无法继续执行,需要在任务中捕获InterruptedException异常并进行适当的清理工作。

总结

优雅地停止线程是编写高质量Java多线程程序的关键之一。在选择停止线程的方法时,需要考虑线程的执行情况、任务特性以及程序设计的要求。一般而言,使用interrupt()方法或者ExecutorService来管理线程是较为推荐的做法,可以有效地避免线程不安全的终止以及资源泄露等问题。

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等

标签:Java,Thread,中断,任务,阿里,线程,停止,true
From: https://www.cnblogs.com/coderacademy/p/18067657

相关文章

  • 「Java开发指南」MyEclipse如何支持Spring Scaffolding?(五)
    在上文中(点击这里回顾>>)主要为大家介绍了SpringDSL模型等内容,本文将继续介绍菜单等。MyEclipsev2023.1.2离线版下载MyEclipse技术交流群:742336981欢迎一起进群讨论6.菜单本节主要描述与Spring支持的MyEclipse相关的各种菜单。6.1MyEclipse菜单当您右键单击Eclipse项目......
  • 面试了一个 5 年 Java 程序员,一个问题也不会。。
    大家好,我是R哥。周末愉快呀,最近我在做Java面试辅导,也模拟面试了好些个学员,说说其中一个学员吧,一个工作5年的Java程序员,模拟面试,居然一个问题也不会。。当晚模拟面试完,我的心情很复杂。我之前做系统架构师,同时也是面试官,这些年,少说也面试过几百上千人,不乏知识渊博、技能顶......
  • 【JavaScript】面试手撕柯里化函数
    ......
  • 图解Java并发编程第一章总结【精炼版】
    【第一章】图解Java并发编程Java线程的基本操作yield操作:yield操作,在基于时间片轮转的cpu调度算法中,用来放弃当前时间片sleep操作:sleep操作分为三种情况普通sleep:在指定时间内放弃cpu使用权,不释放同步锁sleep(0):作用与yield相同sleep被中断:抛出中断异常......
  • 基于SSM的协同过滤算法的电影推荐系统(有报告)。Javaee项目。ssm项目。
    演示视频:基于SSM的协同过滤算法的电影推荐系统(有报告)。Javaee项目。ssm项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringMvc+Mybatis+Vue+Layui+Elementui+Maven来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。报......
  • Java知识点之单例模式
    1、单例模式(BinarySearch)单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但......
  • java毕业设计小众咖啡店推荐平台的设计与实现(springboot+mysql+jdk1.8+meven)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景在当今社会,咖啡已经成为许多人日常生活中不可或缺的一部分。随着人们生活水平的提高和消费观念的转变,越来越多的人开始追求个性化和高品质的咖啡体验。小......
  • java毕业设计线上教学平台(springboot+mysql+jdk1.8+meven)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景随着互联网技术的迅猛发展,线上教育已经成为了现代教学体系中不可或缺的一部分。尤其是在全球性的公共卫生事件影响下,线上教学平台显示出了其独特的优势和......
  • Java 简单 bean 与 json 互相转换
    场景说明最近在写一个服务,经常用到调别人接口得到json,然后需要转换为指定bean,记录一下常用工具类引入依赖<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency><dependency>......
  • 【华为OD】C卷真题 200分:分披萨 JavaScript代码实现[思路+代码]
       C++\python\java\C代码:【华为OD】C卷真题200分:分披萨C/C++代码实现[思路+代码]_第一行为正整数奇数n,表示最小披萨小块数量。3<=n<500-CSDN博客【华为OD】C卷真题200分:分披萨python代码实现[思路+代码]-CSDN博客【华为OD】C卷真题200分:分披萨Java代码实现[思路+......