Java: Java终止线程的几种方式
首先说明,使用stop方法终止的方式已经在很久之前就被废弃了,在加锁的情况下有可能会造成死锁,这里不做讨论。
1. 使用标志位终止线程
在run()方法执行完毕后,该线程就终止了。但是在某些特殊的情况下,希望run()方法中的代码一直循环执行。比如在服务端程序中可能会使用 while(true) { ... } 这样的循环结构来不断的接收来自客户端的请求。此时就可以用修改标志位的方式来结束 run() 方法。例:
public class ServerThread extends Thread {
//volatile修饰符用来保证其它线程读取的总是该变量的最新的值
public volatile boolean exit = false;
@Override
public void run() {
ServerSocket serverSocket = new ServerSocket(8080);
while(!exit){
serverSocket.accept(); //阻塞等待客户端消息
...
}
}
public static void main(String[] args) {
ServerThread t = new ServerThread();
t.start();
...
t.exit = true; //修改标志位,退出线程
}
}
Note:一定要给标志位加上volatle 关键字!详细原因可参考:https://www.cnblogs.com/yongdaimi/p/9566332.html 或者 https://www.cnblogs.com/dolphin0520/p/3920373.html 。
2. 使用interrupt()方法来终止线程
interrupt()方法用于中断线程,调用该方法的线程状态将会被置为“中断状态”。
Note: 线程中断仅仅是置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。java中的那些支持线程中断的方法(也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。
调用这种方式去终止的线程存在两种情况:
第一种情况:该线程循环执行不会存在阻塞
比如,在while 循环中循环打印一句话:这样的话调用interrupt()会立即终止该线程。例:
package com.yongdaimi.java.demo; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; public class Test3 { public static void main(String[] args) {
NotInterruptThread mNotInterruptThread = new NotInterruptThread();
mNotInterruptThread.start(); try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} mNotInterruptThread.interrupt();
} static class NotInterruptThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
System.out.println("=============NotInterruptThread execute... =============");
}
} } }
运行结果:
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
5 秒后,打印就会停止。
第二种情况:该线程循环执行存在阻塞状态
比如,在线程中存在sleep()、await()、wait(long) 这种能够抛出:interruptedException 异常的方法,这种情况调用interrupt()方法后将会触发这些异常,可以选择在触发异常后调用break来终止线程。例:
package com.yongdaimi.java.demo; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; public class Test3 { private static Object sLock = new Object(); private static ReentrantLock sReentrantLock = new ReentrantLock();
private static Condition sSuspendCondition = sReentrantLock.newCondition(); public static void main(String[] args) {
/*NotInterruptThread mNotInterruptThread = new NotInterruptThread();
mNotInterruptThread.start(); try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} mNotInterruptThread.interrupt();
*/ InterruptThread interruptThread = new InterruptThread();
interruptThread.start(); try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
} interruptThread.interrupt(); /*InterruptThread1 interruptThread1 = new InterruptThread1();
interruptThread1.start(); try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} interruptThread1.interrupt();*/ /*InterruptThread2 interruptThread2 = new InterruptThread2();
interruptThread2.start(); try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
e1.printStackTrace();
} interruptThread2.interrupt();*/ /*sReentrantLock.lock();
try {
sSuspendCondition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
sReentrantLock.unlock();
}*/ } static class NotInterruptThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
System.out.println("=============NotInterruptThread execute... =============");
}
} } static class InterruptThread extends Thread { @Override
public void run() {
super.run();
while (!isInterrupted()) {
System.out.println("=============InterruptThread execute... =============");
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
} static class InterruptThread1 extends Thread { @Override
public void run() {
super.run();
while (!isInterrupted()) {
synchronized (sLock) {
System.out.println("=============InterruptThread execute... =============");
try {
sLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
} static class InterruptThread2 extends Thread { @Override
public void run() {
super.run();
while (!isInterrupted()) {
sReentrantLock.lock();
try {
System.out.println("=============InterruptThread execute... =============");
sSuspendCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
break;
} finally {
sReentrantLock.unlock();
}
}
}
} }
我这里分别演示了使用sleep()、wait()、await()的方式来阻塞线程,然后在主线程休眠一段时间后尝试去中断,子线程中收到异常后调用break退出循环,实际试验都可以正常退出循环。
参考链接:
1. interrupt、interrupted 、isInterrupted 区别
Java: Java终止线程的几种方式的更多相关文章
- java中终止线程的三种方式
在java中有三种方式可以终止线程.分别为: 1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止. 2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和sus ...
- Java中终止线程的三种方法
终止线程一般建议采用的方法是让线程自行结束,进入Dead(死亡)状态,就是执行完run()方法.即如果想要停止一个线程的执行,就要提供某种方式让线程能够自动结束run()方法的执行.比如设置一个标志来 ...
- Java中创建线程的两种方式
创建线程的第一种方式: 创建一个类继承Thread 重写Thread中的run方法 (创建线程是为了执行任务 任务代码必须有存储位置,run方法就是任务代码的存储位置.) 创建子类对象,其实就是在创建 ...
- Java终止线程的三种方式
停止一个线程通常意味着在线程处理任务完成之前停掉正在做的操作,也就是放弃当前的操作. 在 Java 中有以下 3 种方法可以终止正在运行的线程: 使用退出标志,使线程正常退出,也就是当 run() 方 ...
- Java值创建线程的两种方式对比
在Java中创建线程的方式有两种,第一种是直接继承Thead类,另一种是实现Runable接口.那么这两种方式孰优孰劣呢? 采用继承Thead类实现多线程: 优势:编写简单,如果需要访问当前线程,只需 ...
- Java 多线程 创建线程的4种方式
1 继承Thread类,重写run方法.Thread类实现了Runnable接口. 2 实现Runnable接口,重写run方法.相比于继承Thread类,可以避免单继承的缺陷和实现资源共享. 举例: ...
- Java中创建线程的三种方式以及区别
在java中如果要创建线程的话,一般有3种方法: 继承Thread类: 实现Runnable接口: 使用Callable和Future创建线程. 1. 继承Thread类 继承Thread类的话,必须 ...
- Java多线程——创建线程的两种方式
创建线程方式一:继承Thread类. 步骤:1,定义一个类继承Thread类.2,覆盖Thread类中的run方法.3,直接创建Thread的子类对象创建线程.4,调用start方法开启线程并调用线程 ...
- Java中创建线程的三种方式及其优缺点
1.自定义一个继承Thread的类,由于Java的单继承特性,限制了该类的扩展性. 2.实现Runnable接口,重写run()方法. 3.实现Callable接口,重写call方法.线程执行体可以有 ...
随机推荐
- Kubernetes学习之原理
Kubernetes基本概念 一.Label selector在kubernetes中的应用场景 1.kube-controller-manager的replicaSet通过定义的label 来筛选要 ...
- Spark排序方式集锦
一.简介 spark中的排序一般可以使用orderBy或sort算子,可以结合负号.ASC/DESC和col进行简单排序.二次排序等情况 二.代码实现 package big.data.analyse ...
- 使用DocumentFormat.OpenXml操作Excel文件.xlsx
1.开始 DocumentFormat.OpenXml是ms官方给一个操作office三大件新版文件格式(.xlsx,.docx,.pptx)的组件:特色是它定义了OpenXml所包含的所有对象(たぶ ...
- MySQL-长事务详解
前言: 『入门MySQL』系列文章已经完结,今后我的文章还是会以MySQL为主,主要记录下近期工作及学习遇到的场景或者自己的感悟想法,可能后续的文章不是那么连贯,但还是希望大家多多支持.言归正传,本 ...
- SpringBoot + Nginx 配置HTTPS的一次经历
最近公司开发了一款小程序的应用,但是小程序为了保证数据安全,强制要求使用HTTPS,然后就不得不去配置了一下. 之前在php开发的项目上配置过一次,使用的是wdcp的控制台程序,配置起来很简单,不需要 ...
- virt-install创建虚拟机并制作成模板
一.使用virt-install创建新的虚拟机 virt--template --ram --vcpu= --virt-type kvm --cdrom=/Data/kvm/iso/CentOS-.i ...
- V-rep(1)
第一次课堂作业,需要导入网格三维模型,对齐坐标系,然后在各个关节添加jiont,实现外观模型和运动仿真模型的分离. 1.首先导入模型.导入模型可能是一个整体模型(装配好的),也可能是单个(mesh)网 ...
- 音视频RTP数据包封装
对于语音通信而言,语音码率较低,添加适当冗余是对抗网络丢包的常见方式.冗余方式有多种,包括RED,FEC等都是冗余的一种,如果冗余份数较多,可以采取交织的方式实现.RFC 3350是RTP的基础标准协 ...
- python 二、八、十六进制之间的快速转换
一.进制转换 1.2 十进制转二进制 bin(18)--> '0b10010' 去掉0b就是10010 即为十进制18转二进制是10010 十进制转八进制oct(18) --> ...
- Markdown插入图表
链接:https://www.jianshu.com/p/3cf83d22dd3d Markdown图表语法 本文介绍如何用Markdown的mermaid等语法插入时序图.流程图.甘特图 如果是想学 ...