原理:new一个Thread对象,如:Thread thread=new Thread(Runnable接口的实现类);然后调用thread.interrupt()方法
使用thread.interrupt(),只是发出中段信号,线程停不停止并不由自己决定,而是由被停止的线程决定,不是强制停止线程。
- 普通情况下停止线程(run内没有sleep或者wait方法),还需要调用!Thread.currentThread().isInterrupted()表示被停止的线程配合接收到中断信号,同时停止线程:
/**
* run内没有sleep或者wait方法时,停止线程
*/
public class RightWayStopThreadWithoutSleep implements Runnable{
@Override
public void run() {
int num=0;
while(!Thread.currentThread().isInterrupted()&&num<=Integer.MAX_VALUE/2){
if(num%10000==0){
System.out.println(num+"是一万的倍数");
}
num++;
}
System.out.println("任务运行结束了");
}
public static void main(String[] args) {
Thread thread=new Thread(new RightWayStopThreadWithoutSleep());
thread.start();
try {
//线程运行一秒钟之后给他截断(进入阻塞?)
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
- 阻塞情况下停止线程(即带sleep方法中断线程):
/**
* 带有sleep方法中断线程
*/
public class RightWayStopThreadWithSleep {
public static void main(String[] args) throws InterruptedException {
Runnable runnable=()->{
int num=0;
try {
while (num <= 300 && !Thread.currentThread().isInterrupted()) {
if (num % 100 == 0) {
System.out.println(num + "是100的倍数");
}
num++;
}
Thread.sleep(10000);//让线程阻塞10秒
}catch (InterruptedException e ){
e.printStackTrace();
}
};
Thread thread=new Thread(runnable);
thread.start();
thread.sleep(9000);//我们在10s处无法中断,因为10s时人家已经没有停止,也就无法中断
thread.interrupt();
}
}
每次迭代(循环)都阻塞情况下停止线程:
/**
* 在使用过程中,每次循环都会调用sleep或wait等方法,那么就不需要每次迭代都要检查是否已经中断
*/
public class RightWayStopThreadEveryLoop {
public static void main(String[] args) throws InterruptedException {
Runnable runnable=()->{
int num=0;
try {
while (num <= 10000) {
if (num % 100 == 0) {
System.out.println(num + "是100的倍数");
}
num++;
System.out.println(Thread.currentThread().getName());
Thread.sleep(100);//让线程阻塞0.01秒,所以出现打印的过程比较慢
//这个过程线程可能就会收到这个通知,将线程停止
}
}catch (InterruptedException e ){
e.printStackTrace();
}
};
Thread thread=new Thread(runnable);
thread.start();
thread.sleep(5000);//让线程运行到第五秒时停止
System.out.println(Thread.currentThread().getName());
thread.interrupt();//发送停止消息,
}
}
这里要注意一种情况:就是while里面方法try/catch的问题,一旦响应中断,会将interrupt标记位清除
/**
* 如果while里面放try-catch,会导致中断失效
*/
public class CantInterrupt {
public static void main(String[] args) throws InterruptedException {
Runnable runnable=()->{
int num=0;
while(num<=10000){
if(num%100==0){
System.out.println(num+"是100的倍数");
}
num++;
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread thread=new Thread(runnable);
thread.start();
Thread.sleep(500);//主动发送信号
System.out.println(Thread.currentThread().getName());
thread.interrupt();
}
}
最佳停止线程的二种方法:
-
优先选择:传递中断,这种方法出现的情况是若在run方法里面有一个方法不是我们写的而是由别的人写的,正因为方法是别人写的,方法里面的具体细节我们并不知道,里面的对异常的处理我们也就不知道,也就不能响应中断了,即使添加检验也无法获取到中断信息。注意,run方法无法抛出受检异常,只能用try/catch
/**
* 最佳实践:catch住了InterruptedException之后优先选择:在方法签名中抛出异常
* 那么在run()就会强制try/catch
*/
public class RightWayStopThreadInProduct implements Runnable{
@Override
public void run() {
while (true){
try {
//这里只提示只能用try/catch
System.out.println("gogo");
throwInMethod();
System.out.println("打印日志");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void throwInMethod() throws InterruptedException {
Thread.sleep(2000);
}
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(new RightWayStopThreadInProduct());
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
}
- 不想或无法传递:恢复中断,在catch字句中调用Thread.currentThread().isInterrupted()
来恢复设置中断状态,以便在后续的执行中,依然能够检查到刚才发生了中断
/**
* 最佳实践2:在catch字句中调用Thread.currentThread().isInterrupted()
* 来恢复设置中断状态,以便在后续的执行中,依然能够检查到刚才发生了中断
*/
public class RightWayStopThreadInProduct2 implements Runnable{
@Override
public void run() {
while (true){
//如果线程已经被中断,这时就可以检测中断信息了
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interruped,程序运行结束");
break;
}
reInterrupe();
}
}
private void reInterrupe() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
//重新设置中断
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(new RightWayStopThreadInProduct2());
thread.start();
Thread.sleep(1000);
thread.interrupt();
}
}
最后补充一点关于异常的信息:Error和RuntimeException都是非检查异常,也即是编译器无法预测的,而其他的异常都是受检查异常