Java中的interrupt()中断线程(Interrupt 方法结束线程)-- 转载

很多Java初级开发者(包括我)都知道终止一个正在运行的线程最好的方法不是JDK已废弃的stop()方法,而是用interrupt()或条件变量,但事实上真就那么简单吗?

中断可以理解为线程的一个标志位属性,它表示一个运行中的线程是否被其他线程进行了中断操作。中断好比其它线程对该线程打了个招呼,其它线程通过调用该线程的interrupt()方法对其进行中断操作,相当于将该线程的中断标志位设置为true,而被中断的线程自身通过检查中断标志位做出中断响应,说白了,就是我们程序员自己写中断处理程序的代码(因为JDK的开发者并不知道我们中断线程后如何处理未完成的任务)。这里演示一段代码,表明单纯用interrupt()中断线程方法并不能停止当前正在运行的线程,需要配合其它方法才能正确停止线程。

public class InterruptDemo {
	static class MyRunnable implements Runnable{
 
		public void run() {
			for(int i=0;i<50000;i++)
			{
				System.out.println("i="+(i+1));
				
			}
		}
		
	}
	public static void main(String[] args) {
		Thread t=new Thread(new MyRunnable());
		t.start();
		t.interrupt();
	}
}

看控制台输出结果:

在这里插入图片描述
可见,线程一直打印到50000,执行完毕后退出线程,并没有我们预料中在某处中断。

结论: 单纯用 interrupt()中断线程方法并不能停止当前正在运行的线程,需要配合其它方法才能正确停止线程。

这里的其它方法包括:interrupted()与isInterrupted(),两者都是判断当前线程 的中断标志位是否为true,两者都是唯一区别是,前者会读取并清除中断状态,后者仅读取状态。意思是,假如当前线程已经被调用 interrupt()方法将中断标志位设为true,那么在调用interrupted()方法首先会返回一个true,然后将其中断标志位设为false,而如果调用isInterrupted()方法,始终会返回true,其中断标志位不变。程序中建议慎用interrupted()方法,而使用isInterrupted()方法,不过应根据业务需求和底层原理灵活使用,这就考虑程序员的能力了。下面配合isInterrupted()方法完成对上面代码的改进,让其在某处中断下来。

public class InterruptDemo2 {
	static class MyRunnable implements Runnable{
 
		public void run() {
			for(int i=0;!Thread.currentThread().isInterrupted()&&i<50000;i++)
			{
				System.out.println("i="+(i+1));
			}
		}
		
	}
	public static void main(String[] args) throws InterruptedException {
		Thread t=new Thread(new MyRunnable());
		t.start();
		Thread.currentThread().sleep(5);//让线程运行一段时间
		t.interrupt();
		t.join();//等待指定的线程终止
		System.out.println("end");
	}

看控制台输出结果:
在这里插入图片描述
这里完成了一个简单的中断处理程序。但令人困惑的还不止这两个方法,我们在继 续深入下去,最后给出Java中断线程的最佳实践和模板代码。

当一个正在运行的线程遇到阻塞时,中断该线程的情况将变得更加复杂和麻烦,这 里为方便起见,仅举出遇到wait/sleep/join阻塞后,调用 interrupt()方法的情况。

查阅JDK文档,可知:如果该线程正阻塞于Object类的wait()、wait(long)、 wait(long, int)方法,或者Thread类的join()、join(long)、join(long, int)、sleep(long)、sleep(long, int)方法,则该线程的中断状态将被清除(即 中断标志位设为false ),并收到一个java.lang.InterruptedException。

因此 , (画重点,敲黑板!) 在编写多线程代码的时候,任何时候捕获到
InterruptedException, 要么继续上抛,要么重置中断状态,这是最安全的做法.

模板代码:

public void run() {
    try {
          // ① 调用阻塞方法
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();    // ② 恢复被中断的状态
        }
}

这里举个例子:

public class InterruptDemo3 {
	static class MyRunnable implements Runnable{
 
		public void run() {
			while(!Thread.currentThread().isInterrupted()){
				try {
					System.out.println("sleep begin!");
					Thread.currentThread().sleep(1000);
					System.out.println("sleep end!");
				} catch (InterruptedException e) {
					System.out.println("睡眠中遇中断进入catch,重置中断标志位,退出循环!");
					Thread.currentThread().interrupt();//中断标志位为true 退出循环
				}
				
			}
			System.out.println("中断后正常退出");
			
		}
		
	}
	public static void main(String[] args) throws InterruptedException {
		Thread t=new Thread(new MyRunnable());
		t.start();
		Thread.currentThread().sleep(1000);//让线程t运行一段时间
		t.interrupt();
	}
}

看控制台输出结果:
在这里插入图片描述
假如将13行注释起来,线程将无法中断,一直循环下去。

所以说,线程中断还真不是一个简单的问题,中断后的处理程序要程序员自己写, 一定要慎之又慎。在工作中必须灵活运用,知道原理和处理方法。

————————————————
版权声明:本文为CSDN博主「罗啦啦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_24693837/article/details/71601044

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值