对于启动一个线程都知道如何启动,但是对于中断一个线程呢,例如在线程持续处理业务时,由于处理逻辑中有访问接口异常,在接口恢复后再对数据进行处理,以免出现大量错误数据,那么采用什么方式进行中断,需要谨慎的选择,Thread的api中提供了几个方式进行中断,stop()、suspend()都已经标记为过时,因为存在安全问题,再这里主要对两种中断方式做讲解。
方式 | 说明 |
---|---|
设置标志 | 在线程中设置标志位来判断是否暂停 |
interrupt() | 中断线程,这时只是标记要中断,实际什么时间暂停将由计算机决定 |
设置标志方式
首先创建一个线程类并且声明volatile的Boolean的标志。
/**
* @author : Erick
* @version : 1.0
* @Description :
* @time :2019-4-19
*/
public class JmsThread implements Runnable {
//volatile可见性,变量变更始终从主存中获取最新值,而不存在延迟。
volatile Boolean keepRunning = true;
@Override
public void run() {
while (true){
//判断标志是否为true
if (keepRunning){
System.out.println("当前运行线程为:" +Thread.currentThread().getName());
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
编写测试类
import java.util.HashMap;
import java.util.Map;
/**
* @author : Erick
* @version : 1.0
* @Description :
* @time :2019-4-19
*/
public class TestJms {
static Map<Integer , Runnable> QueueMap = new HashMap<Integer, Runnable>();
public static void main(String[] args) {
//开启10个线程运行
for (int i = 0; i < 10; i++) {
JmsThread jmsThread = new JmsThread();
Thread thread = new Thread(jmsThread);
thread.setName("线程名称:"+i);
QueueMap.put(i,jmsThread);
thread.start();
}
//让所有线程运行5s。
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//将每个线程中的标志都设置为false
for (int i = 0; i < 9; i++) {
JmsThread jmsThread = (JmsThread) QueueMap.get(i);
jmsThread.keepRunning = false;
}
System.out.println("线程0-8已经暂停");
try {
//运行10s
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//再将标志为置为true
for (int i = 0; i < 9; i++) {
JmsThread jmsThread = (JmsThread) QueueMap.get(i);
jmsThread.keepRunning = true;
}
System.out.println("线程0-8已经启动");
}
}
输出结果,开始的5s所有线程随机运行,等把前9个线程标志位更改为false后则只有一个线程9在运行,线程内有1s的等待,这里会输出10次,然后将标志位更改为true,又会将所有线程启动运行。
当前运行线程为:线程名称:1
当前运行线程为:线程名称:2
当前运行线程为:线程名称:3
当前运行线程为:线程名称:4
当前运行线程为:线程名称:5
当前运行线程为:线程名称:8
当前运行线程为:线程名称:7
当前运行线程为:线程名称:6
当前运行线程为:线程名称:9
当前运行线程为:线程名称:2
当前运行线程为:线程名称:1
当前运行线程为:线程名称:0
当前运行线程为:线程名称:3
当前运行线程为:线程名称:5
当前运行线程为:线程名称:4
当前运行线程为:线程名称:9
当前运行线程为:线程名称:6
当前运行线程为:线程名称:7
当前运行线程为:线程名称:8
线程0-8已经暂停
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
当前运行线程为:线程名称:9
线程0-8已经启动
当前运行线程为:线程名称:0
当前运行线程为:线程名称:3
当前运行线程为:线程名称:1
当前运行线程为:线程名称:2
当前运行线程为:线程名称:9
当前运行线程为:线程名称:6
当前运行线程为:线程名称:8
当前运行线程为:线程名称:4
当前运行线程为:线程名称:5
当前运行线程为:线程名称:7
当前运行线程为:线程名称:1
当前运行线程为:线程名称:0
当前运行线程为:线程名称:3
当前运行线程为:线程名称:2
当前运行线程为:线程名称:9
当前运行线程为:线程名称:6
当前运行线程为:线程名称:7
当前运行线程为:线程名称:5
当前运行线程为:线程名称:8
当前运行线程为:线程名称:4
当前运行线程为:线程名称:1
当前运行线程为:线程名称:3
当前运行线程为:线程名称:0
当前运行线程为:线程名称:2
当前运行线程为:线程名称:9
使用interrupt()进行中断
/**
* @author : Erick
* @version : 1.0
* @Description :
* @time :2019-6-13
*/
public class InterruptTest {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(Thread.currentThread().getName());
}
}
});
thread.setName("aaaaa");
thread.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
System.out.println("线程已经暂停");
}
}
而结果呢,线程不会因为中断请求而中断线程本身的操作,还是会继续执行。
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
线程已经暂停
aaaaa
aaaaa
aaaaa
aaaaa
通过interrupt方式只是通知要中断线程,具体什么时间中断是靠机器本身来决定的。