太难了!面试官居然要我停止一个正在运行的线程?

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
简介: 停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop()方法,但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。

停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop()方法,但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。

在java中有以下3种方法可以终止正在运行的线程:

  1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
  2. 使用stop方法强行终止,但是不推荐这个方法,因为stop和suspend及resume一样都是过期作废的方法。
  3. 使用interrupt方法中断线程。

1. 停止不了的线程

interrupt()方法的使用效果并不像for+break语句那样,马上就停止循环。调用interrupt方法是在当前线程中打了一个停止标志,并不是真的停止线程。

输出结果:

2. 判断线程是否停止状态

Thread.java类中提供了两种方法:

  1. this.interrupted(): 测试当前线程是否已经中断;
  2. this.isInterrupted(): 测试线程是否已经中断;

那么这两个方法有什么图区别呢?

我们先来看看this.interrupted()方法的解释:测试当前线程是否已经中断,当前线程是指运行this.interrupted()方法的线程。

运行结果:

??
 ??

类Run.java中虽然是在thread对象上调用以下代码:thread.interrupt(), 后面又使用

(" 1??" + ());
(" 2??" + ());

来判断thread对象所代表的线程是否停止,但从控制台打印的结果来看,线程并未停止,这也证明了interrupted()方法的解释,测试当前线程是否已经中断。这个当前线程是main,它从未中断过,所以打印的结果是两个false.

如何使main线程产生中断效果呢?

运行效果为:

??
 ??

方法interrupted()的确判断出当前线程是否是停止状态。但为什么第2个布尔值是false呢?官方帮助文档中对interrupted方法的解释:

测试当前线程是否已经中断。线程的中断状态由该方法清除。

换句话说,如果连续两次调用该方法,则第二次调用返回false。

下面来看一下inInterrupted()方法。

运行结果:

??
 ??

isInterrupted()并为清除状态,所以打印了两个true。

3. 能停止的线程--异常法

有了前面学习过的知识点,就可以在线程中用for语句来判断一下线程是否是停止状态,如果是停止状态,则后面的代码不再运行即可:

运行结果:

上面的示例虽然停止了线程,但如果for语句下面还有语句,还是会继续运行的。看下面的例子:

使用Run.java执行的结果是:

如何解决语句继续运行的问题呢?看一下更新后的代码:

使用Run.java运行的结果如下:

4. 在沉睡中停止

如果线程在sleep()状态下停止线程,会是什么效果呢?

使用Run.java运行的结果是:

从打印的结果来看, 如果在sleep状态下停止某一线程,会进入catch语句,并且清除停止状态值,使之变为false。

前一个实验是先sleep然后再用interrupt()停止,与之相反的操作在学习过程中也要注意:

运行结果:

5. 能停止的线程---暴力停止

使用stop()方法停止线程则是非常暴力的。

运行结果:

6.方法stop()与java.lang.ThreadDeath异常

调用stop()方法时会抛出java.lang.ThreadDeath异常,但是通常情况下,此异常不需要显示地捕捉。

stop()方法以及作废,因为如果强制让线程停止有可能使一些清理性的工作得不到完成。另外一个情况就是对锁定的对象进行了解锁,导致数据得不到同步的处理,出现数据不一致的问题。

7. 释放锁的不良后果

使用stop()释放锁将会给数据造成不一致性的结果。如果出现这样的情况,程序处理的数据就有可能遭到破坏,最终导致程序执行的流程错误,一定要特别注意:

public class SynchronizedObject {    private String name = "a";    private String password = "aa";    public synchronized void printString(String name, String password){        try {            this.name = name;            Thread.sleep(100000);            this.password = password;        } catch (InterruptedException e) {            e.printStackTrace();        }    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }}public class MyThread extends Thread {    private SynchronizedObject synchronizedObject;    public MyThread(SynchronizedObject synchronizedObject){        this.synchronizedObject = synchronizedObject;    }    public void run(){        synchronizedObject.printString("b", "bb");    }}public class Run {    public static void main(String args\[\]) throws InterruptedException {        SynchronizedObject synchronizedObject = new SynchronizedObject();        Thread thread = new MyThread(synchronizedObject);        thread.start();        Thread.sleep(500);        thread.stop();        System.out.println(synchronizedObject.getName() + "  " + synchronizedObject.getPassword());    }}

输出结果:

b  aa

由于stop()方法以及在JDK中被标明为“过期/作废”的方法,显然它在功能上具有缺陷,所以不建议在程序张使用stop()方法。

8. 使用return停止线程

将方法interrupt()与return结合使用也能实现停止线程的效果:

public class MyThread extends Thread {    public void run(){        while (true){            if(this.isInterrupted()){                System.out.println("线程被停止了!");                return;            }            System.out.println("Time: " + System.currentTimeMillis());        }    }}public class Run {    public static void main(String args\[\]) throws InterruptedException {        Thread thread = new MyThread();        thread.start();        Thread.sleep(2000);        thread.interrupt();    }}

输出结果:

...Time: 1467072288503Time: 1467072288503Time: 1467072288503线程被停止了!

不过还是建议使用“抛异常”的方法来实现线程的停止,因为在catch块中还可以将异常向上抛,使线程停止事件得以传播。


本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。

相关文章
|
30天前
|
Oracle Java 关系型数据库
一次惨痛的面试:“网易提前批,我被虚拟线程问倒了”
【5月更文挑战第13天】一次惨痛的面试:“网易提前批,我被虚拟线程问倒了”
52 4
|
1月前
|
消息中间件 前端开发 Java
美团面试:如何实现线程任务编排?
线程任务编排指的是对多个线程任务按照一定的逻辑顺序或条件进行组织和安排,以实现协同工作、顺序执行或并行执行的一种机制。 ## 1.线程任务编排 VS 线程通讯 有同学可能会想:那线程的任务编排是不是问的就是线程间通讯啊? 线程间通讯我知道了,它的实现方式总共有以下几种方式: 1. Object 类下的 wait()、notify() 和 notifyAll() 方法; 2. Condition 类下的 await()、signal() 和 signalAll() 方法; 3. LockSupport 类下的 park() 和 unpark() 方法。 但是,**线程通讯和线程的任务编排是
26 1
|
1月前
|
Java 数据库连接 调度
面试题:用过线程池吗?如何自定义线程池?线程池的参数?
字节跳动面试题:用过线程池吗?如何自定义线程池?线程池的参数?
35 0
|
10天前
|
缓存 Java 调度
java面试题之个人对线程池的理解
java面试题之个人对线程池的理解
|
28天前
|
消息中间件 安全 前端开发
小米面试:如何实现优先级线程池?
我们知道,线程池中的所有线程都是由统一的线程工厂来创建的,当我们指定线程工厂时,线程池中的所有线程会使用我们指定的线程工厂来创建线程;但如果没有指定线程工厂,则会使用默认的线程工厂 DefaultThreadFactory 来创建线程,核心源码如下: ```java DefaultThreadFactory() { @SuppressWarnings("removal") SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() :
38 1
小米面试:如何实现优先级线程池?
|
5天前
|
设计模式 NoSQL Java
网易面试:SpringBoot如何开启虚拟线程?
虚拟线程(Virtual Thread)也称协程或纤程,是一种轻量级的线程实现,与传统的线程以及操作系统级别的线程(也称为平台线程)相比,它的创建开销更小、资源利用率更高,是 Java 并发编程领域的一项重要创新。 > PS:虚拟线程正式发布于 Java 长期支持版(Long Term Suort,LTS)Java 21(也就是 JDK 21)。 虚拟线程是一种在 Java 虚拟机(JVM)层面实现的逻辑线程,不直接和操作系统的物理线程一一对应,因此它可以减少上下文切换所带来的性能开销。 操作系统线程、普通线程(Java 线程)和虚拟线程的关系如下: ![image.png](https:
15 0
网易面试:SpringBoot如何开启虚拟线程?
|
10天前
|
监控 Java
面试官:说一说如何优雅的关闭线程池,我:shutdownNow,面试官:粗鲁!
【6月更文挑战第4天】面试官:说一说如何优雅的关闭线程池,我:shutdownNow,面试官:粗鲁!
8 0
|
11天前
|
Java Apache Spring
面试官:如何自定义一个工厂类给线程池命名,我:现场手撕吗?
【6月更文挑战第3天】面试官:如何自定义一个工厂类给线程池命名,我:现场手撕吗?
10 0
|
17天前
|
消息中间件 监控 Java
滴滴面试:谈谈你对Netty线程模型的理解?
Netty 线程模型是指 Netty 框架为了提供高性能、高并发的网络通信,而设计的管理和利用线程的策略和机制。 **Netty 线程模型被称为 Reactor(响应式)模型/模式,它是基于 NIO 多路复用模型的一种升级,它的核心思想是将 IO 事件和业务处理进行分离,使用一个或多个线程来执行任务的一种机制。** ## 1.**Reactor三大组件** Reactor 包含以下三大组件: ![image.png](https://cdn.nlark.com/yuque/0/2024/png/92791/1717079218890-89000a00-48bc-4a1a-b87e-e1b6
26 2
|
1月前
|
消息中间件 监控 前端开发
面试官:核心线程数为0时,线程池如何执行?
线程池是 Java 中用于提升程序执行效率的主要手段,也是并发编程中的核心实现技术,并且它也被广泛的应用在日常项目的开发之中。那问题来了,如果把线程池中的核心线程数设置为 0 时,线程池是如何执行的? 要回答这个问题,我们首先要了解在正常情况下,线程池的执行流程,也就是说当有一个任务来了之后,线程池是如何运行的? ## 1.线程池的执行流程 正常情况下(核心线程数不为 0 的情况下)线程池的执行流程如下: 1. **判断核心线程数**:先判断当前工作线程数是否大于核心线程数,如果结果为 false,则新建线程并执行任务。 2. **判断任务队列**:如果大于核心线程数,则判断任务队列是否
39 1
面试官:核心线程数为0时,线程池如何执行?