Thread 如何安全结束一个线程 MD
Markdown版本笔记 | 我的GitHub首页 | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目录
如何安全的结束一个正在运行的线程
Thread类相关的方法
使用退出标志
使用 interrupt 方法
使用 interrupt() + InterruptedException
使用 interrupt() + isInterrupted()
一个综合案例
不能结束的情况
如何安全的结束一个正在运行的线程
Thread类相关的方法
java.lang.Thread
类包含了一些常用的方法,如:start(), stop(), stop(Throwable) ,suspend(), destroy() ,resume()。通过这些方法,我们可以对线程进行方便的操作,但是这些方法中,只有start()
方法得到了保留。
在JDK帮助文档以及Sun公司的一篇文章《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》
中都讲解了舍弃这些方法的原因。
简单来说是因为:使用stop方法虽然可以强行终止
正在运行或挂起的线程,但使用stop方法是很危险
的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,因此,并不推荐使用stop方法来终止线程。
那么,我们究竟应该如何停止线程呢?
- 1、任务中一般都会有循环结构,只要用一个标记控制住循环,就可以结束任务。
- 2、如果线程处于了
冻结状态
,无法读取标记,此时可以使用interrupt()
方法将线程从冻结状态强制恢复到运行状态中
来,让线程具备CPU的执行资格。
使用退出标志
当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的,如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。
在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。
public class Test {
public static volatile boolean exit = false;//退出标志
public static void main(String[] args) {
new Thread() {
public void run() {
System.out.println("线程启动了");
while (!exit) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程结束了");
};
}.start();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
exit = true;//5秒后更改退出标志的值
}
}
使用 interrupt 方法
如果一个线程由于等待某些事件的发生而被阻塞,又该怎样停止该线程呢?
这种情况经常会发生,比如当一个线程由于需要等候键盘输入而被阻塞,或者调用Thread.join()
方法,或者Thread.sleep()
方法,在网络中调用ServerSocket.accept()
方法,或者调用了DatagramSocket.receive()
方法时,都有可能导致线程阻塞,使线程处于处于不可运行状态
时,即使主程序中将该线程的共享变量设置为true,但该线程此时根本无法检查循环标志,当然也就无法立即中断。
这时建议不要使用stop()方法,而是使用Thread提供的interrupt()
方法,因为该方法虽然不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码
。
使用 interrupt() + InterruptedException
线程处于阻塞状态,如Thread.sleep、wait、IO阻塞
等情况时,调用interrupt方法后,sleep等方法将会抛出一个InterruptedException:
public class Test {
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
System.out.println("线程启动了");
try {
Thread.sleep(1000 * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程结束了");
}
};
thread.start();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();//作用是:在线程阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态
}
}
使用 interrupt() + isInterrupted()
public class Test {
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
System.out.println("线程启动了");
while (!isInterrupted()) {
System.out.println(isInterrupted());//调用 interrupt 之后为true
}
System.out.println("线程结束了");
}
};
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
System.out.println("线程是否被中断:" + thread.isInterrupted());//true
}
}
一个综合案例
public class Test {
static boolean flag = true;
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始休眠");
try {
Thread.sleep(100 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束休眠,开始死循环");
while (flag) {
}
System.out.println("------------------子线程结束------------------");
}
});
thread.start();
Scanner scanner = new Scanner(System.in);
System.out.println("输入1抛出一个中断异常,输入2修改循环标志位,输入3判断线程是否阻塞,输入其他结束Scanner\n");
while (scanner.hasNext()) {
String text = scanner.next();
System.out.println("你输入了:" + text + "\n");
if ("1".equals(text)) {
thread.interrupt();
} else if ("2".equals(text)) {
flag = false; //如果不设为false,主线程结束后子线程仍在运行
} else if ("3".equals(text)) {
System.out.println(thread.isInterrupted());
} else {
scanner.close();
break;
}
}
System.out.println("------------------主线程结束------------------");
}
}
不能结束的情况
注意下面这种是根本不能结束的情况!
public class Test {
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
System.out.println("线程启动了");
while (true) {//对于这种情况,即使线程调用了intentrupt()方法并且isInterrupted(),但线程还是会继续运行,根本停不下来!
System.out.println(isInterrupted());//调用interrupt之后为true
}
}
};
thread.start();
thread.interrupt();//注意,此方法不会中断一个正在运行的线程,它的作用是:在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态
while (true) {
System.out.println("是否isInterrupted:" + thread.isInterrupted());//true
}
}
}
2019-5-8
Thread 如何安全结束一个线程 MD的更多相关文章
- C#如何优雅的结束一个线程
大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...
- THRDTERM-----干净地结束一个线程
THRDTERM产生两个线程.周期性地检查一个event对象.以决定要不要结束自己. #define WIN32_LEAN_AND_MEAN #include<stdio.h> #incl ...
- android 如何结束一个线程
总结: 1 不推荐直接调用onstop()强制结束,,因为不安全 2 run()比较短暂,执行完毕会自动停止 3 在run()设置一个flag标识,满足条件才执行; 4 通过sleep()捕获异常,在 ...
- C# 启动和结束一个线程
在程序执行中会遇到启动本软件的exe问,或者启用其它的exe文件,已达到执行某些操作的作用.下面是两种最常见的启动exe文件. 1.调用系统dll使用其提供的方法. 引用的dll, [DllImpor ...
- 第5章 不要让线程成为脱缰的野马(Keeping your Threads on Leash) ---干净的终止一个线程
干净的终止一个线程 我曾经在第2章产生一个后台线程,用以输出一张屏幕外的 bitmap 图.我们必须解决的一个最复杂的问题就是,如果用户企图结束程序,而这张bitmap 图尚未完成,怎么办?第2章的 ...
- Java 如何正确停止一个线程
自己在做实验性小项目的时候,发现自己遇到一个问题:如何控制线程的"死亡"? 首先,如何开启一个线程呢? 最简单的代码: public class Main { public sta ...
- Java并发(基础知识)—— 创建、运行以及停止一个线程
在计算机世界,当人们谈到并发时,它的意思是一系列的任务在计算机中同时执行.如果计算机有多个处理器或者多核处理器,那么这个同时性是真实发生的:如果计算机只有一个核心处理器那么就只是表面现象. 现代所有的 ...
- 一个线程加一运算,一个线程做减一运算,多个线程同时交替运行--synchronized
使用synchronized package com.pb.thread.demo5; /**使用synchronized * 一个线程加一运算,一个线程做减法运算,多个线程同时交替运行 * * @a ...
- 第5章 不要让线程成为脱缰的野马(Keeping your Threads on Leash) ----初始化一个线程
使用线程的一个常见问题就是如何能够在一个线程开始运行之前,适当地将它初始化.初始化最常见的理由就是为了调整优先权.另一个理由是为了在SMP 系统中设定线程比较喜欢的 CPU.第10 章谈到 MFC 时 ...
随机推荐
- jmeter 常用插件
一.下载安装及使用 下载地址:https://jmeter-plugins.org/install/Install/ 安装:下载后文件为plugins-manager.jar格式,将其放入jmeter ...
- RK3399 修改系统默认语言为简体中文
CPU:RK3288 系统:Android 7.1 修改系统默认语言为简体中文 diff --git a/build/target/product/full_base.mk b/build/targe ...
- RK3399 4G模块移远EC20移植调试
转载请注明出处:https://www.cnblogs.com/lialong1st/p/11266330.html CPU:RK3399 系统:Android 7.1 1.通过串口打印或者adb获取 ...
- 表单Content-Type为multipart/form-data时,后台数据的接收
我们在写form提交表单的时候,后台大多数用request.getParameter的方式来接收前台输入的数据.但如果我们表单中提交的数据包含file文件传输的话,我们需要将Content-Type改 ...
- Flutter移动电商实战 --(43)详细页_补充首页跳转到详细页
首页轮播点击到详细页 修改我们轮播这里的代码:SwiperDiy这个类这里的代码 return InkWell( onTap: (){ Application.router.navigateTo(co ...
- 获取用户当前位置信息的两种方法——H5、微信
在之前的 调用百度地图API的总结 中获取当前位置信息我用的是 H5 ,其实微信也提供了获取用户地理位置的方法,现将这两种方法都贴出来,看情况选择使用. 一.H5 获取当前地理位置得到经纬度 // H ...
- 如何十倍提高你的webpack构建效率
前言 http://jafeney.com/2016/07/10/2016-07-10-webpack/ webpack 是个好东西,和 NPM 搭配起来使用管理模块实在非常方便.而 Babe ...
- 学习笔记——C++编程cin测试记录
cin读取输入流,遇到空格会暂停,下次继续读入剩下的,+++. #include <iostream> using namespace std; int main() { cout< ...
- python定义接口继承类
zxq547 python定义接口继承类invalid syntax解决办法 1 2 3 4 5 6 7 class s_all(metaclass=abc.ABCMeta): #python ...
- javascript——语法 && 结构
原文链接:Understanding Syntax and Code Structure