java线程中断的关键API介绍及使用场景说明

线程中断的方式

Java提供了线程的中断机制:设置线程的中断标志,我们可以使用它来结束一个线程。通过设置线程的中断标志并不能直接终止该线程的执行,这种机制要求线程自己检查它是否被中断了,然后决定是不是要相应这个中断请求。

线程中断相关的API

  • void interrupt():中断线程,例如线程A运行时,线程B可以调用线程A的interrupt方法来设置线程A的中断标志位true。注意:这里仅仅是设置了标志,线程A并没有中断,它会继续往下执行。如果线程A调用了wait系列函数,join方法或sleep方法而被阻塞挂起,这时候如果线程B调用了线程A的interrupt()方法,线程A会在调用这些方法的地方抛出InterruptedException异常而返回。
  • boolean isInterrupted():检测当前线程是否被中断,如果是返回true,否则返回false.
  • boolean interrupted():检测当前线程是否被中断,如果是返回true,否则返回false;这个方法是Thread类的静态方法;另外与interrupt()方法的区别在于,如果发现当前线程被中断,则会清除中断 标志;另外需要注意的是:interrupted()方法是获取当前调用线程(正在运行的线程)的中断标志而不是调用interrupted()方法的实例对象的中断标志。(关键字:检测中断标志并清除中断标志)

线程中断的示例

public class InterruptTest {
	
	public static void main(String[] args) throws InterruptedException {
		
		
		Thread threadA = new Thread(new Runnable() {
			
			@Override
			public void run() {
				//如果线程没有被中断
				while(!Thread.currentThread().isInterrupted()) {
					System.out.println(Thread.currentThread() + "hello...");
				}
				if (Thread.currentThread().interrupted()) {  //这里说明这个方法会清除中断标志
					System.out.println(Thread.currentThread() + " interrupted flag is " + Thread.currentThread().isInterrupted());
				}
                
			}
		});
		
		//启动子线程
		threadA.start();
		
		//主线程休眠1s,以便于中断前让子线程输出
		Thread.sleep(1000);
		
		System.out.println("main thread interrupt thread");
		
		threadA.interrupt();
		
		//等待子线程执行完毕
		threadA.join();
		
		System.out.println("main is over");
		
	}

}

输出结果:

Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
main thread interrupt thread
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main] interrupted flag is false
main is over

代码说明:

if (Thread.currentThread().interrupted()) {  //这里说明这个方法会清除中断标志
	System.out.println(Thread.currentThread() + " interrupted flag is " + Thread.currentThread().isInterrupted());
}
//这种写法和下面的写法作用是一样的,这两种写法都是说明要为当前正在执行的线程设置中断标志
if (Thread.interrupted()) {  //这里说明这个方法会清除中断标志
	System.out.println(Thread.currentThread() + " interrupted flag is " + Thread.currentThread().isInterrupted());
}

sleep过程中被打断

补充一下场景:当线程为了等待一些特定的条件的到来,一般会调用sleep函数、wait系列函数或者join()函数来阻塞挂起当前线程。那举例来说,一个线程条用sleep函数休眠10s来等待条件满足,但是它可能等了3秒条件就满足了,一直等到10s有点浪费时间,这个时候就可以调用该线程的interrupt()方法,强制sleep方法抛出InterruptedException异常而返回,线程回复到激活状态。

public class SleepInterrupt {
	public static void main(String[] args) throws InterruptedException {
		Thread threadA = new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					System.out.println("threadA begin to sleep for 2000 seconds");
					Thread.sleep(2000000);
					System.out.println("threadA awaking");
				}
				catch (InterruptedException e) {
					System.out.println("threadA is interrupted while sleeping");
					return;
				}
				
				System.out.println("threadA leaving normally");
			}
		});
		
		threadA.start();
		//确保子线程进入休眠状态
		Thread.sleep(1000);
		//打断子线程
		threadA.interrupt();
		//等待子线程执行完毕
		threadA.join();
		System.out.println("main thread is over");
	}
}

程序输出:

threadA begin to sleep for 2000 seconds
threadA is interrupted while sleeping
main thread is over

interrupted vs interrupt

public class interruptedTest {
	public static void main(String[] args) throws InterruptedException {
		
		Thread threadOne = new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (;;) {

				}
			}
		});
		
		//启动线程
		threadOne.start();
		
		//设置中断标志
		threadOne.interrupt();
		
		//获取中断标志
		System.out.println("isInterrupted:" + threadOne.isInterrupted());
		
		//获取中断标志并重置
		System.out.println("isInterrupted:" + Thread.interrupted());
		
		//获取中断标志
		System.out.println("isInterrupted:" + threadOne.isInterrupted());
		
		threadOne.join();
		
		System.out.println("main thread is over");
	}
}

程序输出:

isInterrupted:true
isInterrupted:false
isInterrupted:true

分析:第一行输出是因为threadOne.interrupt();设置了threadOne的中断标志;

第二行输出:因为Thread.interrupted()判断的是当前正在执行的线程,也可就是主线程的中断标志;

第三行输出:因为这里判断的也是threadOne的中断标志;

最终threadOne并没有被中断还是一直在空跑,因此最终main thread is over也没有输出。

下面修改下程序:

public class interruptedTest {
	public static void main(String[] args) throws InterruptedException {
		
		Thread threadOne = new Thread(new Runnable() {
			
			@Override
			public void run() {
				//中断标志位true就会退出循环,并且清除中断标志
				while(!Thread.currentThread().interrupted()) {
					
				}
				System.out.println("threadOne isInterrupted:" + Thread.currentThread().isInterrupted());
			}
		});
		
		//启动线程
		threadOne.start();
		
		//设置中断标志
		threadOne.interrupt();
		
		threadOne.join();
		
		System.out.println("main thread is over");
	}
}

程序输出:

threadOne isInterrupted:false
main thread is over

分析:第一行输出,因为执行了threadOne.interrupt();之后threadOne中再执行interrupted()方法,可以检测到线程被设置了中断标志,再执行Thread.currentThread().isInterrupted()检测不出中断标志了,因为被while条件里面的interrupted()方法中断了。

第二行输出,因为threadOne执行完之后,threadOne.join()返回了,main线程不再阻塞,继续执行了下面的语句,输出了main thread is over

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值