Java-interrupt方法的一个小的注意点

Java-interrupt方法的一个小的注意点

记录Java 中 interupt() 方法的一个小的知识点。

开发过程中,经常有需要去终止线程,终止线程的方式无外乎有两种 标志位interrupt(), 前者没什么好说的,就是定义一个bool类型的变量,只是需要注意将该变量声明成 volatile。后者的话主要用于终止带阻塞状态的线程,当然也可以用来终止不带阻塞状态的线程,这里再来复习一下:

关于终止线程的介绍,可参考:Java: Java终止线程的几种方式

终止不带阻塞状态的线程

TaskCase.java

package com.yongdaimi.dmeo;


public class TaskCase {

	private Thread mTaskThread;
	
	public void start() {
		mTaskThread = new Thread() {
			
			@Override
			public void run() {
				super.run();
				
				System.out.println(Thread.currentThread().getName()+" start running...");
				
				// 模拟重复执行的任务
				while (!Thread.currentThread().isInterrupted()) {
					System.out.println("doSomething");
				}
				
				System.out.println(Thread.currentThread().getName()+" stop running...");
				
			}
			
		};
		mTaskThread.start();
	}
	
	/**
	 * 使用此方法进行终止
	 */
	public void calcel() {
		mTaskThread.interrupt();
	}
	
	
}

Test.java

package com.yongdaimi.dmeo;

public class Test {

	public static void main(String[] args) {
		
		
		TaskCase task = new TaskCase();
		task.start();
		
		// 2s 后将测试线程终止
		try {
			Thread.currentThread().sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		task.calcel();
		
	}
	
}

运行:

doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
doSomething
Thread-0 stop running...

可以看到使用此方法,2秒后是可以将执行线程正常终止的。

那如果加了阻塞状态呢?

TaskCase.java

package com.yongdaimi.dmeo;


public class TaskCase {

	private Thread mTaskThread;
	
	public void start() {
		mTaskThread = new Thread() {
			
			@Override
			public void run() {
				super.run();
				
				System.out.println(Thread.currentThread().getName()+" start running...");
				
				// 模拟重复执行的任务
				while (!Thread.currentThread().isInterrupted()) {
					System.out.println("doSomething");
					
					// 模拟阻塞 500ms
					try {
						Thread.currentThread().sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
				System.out.println(Thread.currentThread().getName()+" stop running...");
				
			}
			
		};
		mTaskThread.start();
	}
	
	/**
	 * 使用此方法进行终止
	 */
	public void calcel() {
		mTaskThread.interrupt();
	}
	
	
}

这里在线程中添加一段code, 使线程临时阻塞500ms, 再次执行:

image-20221209152859986

这时发现虽然有走到异常的代码块里,但是线程仍然能够正常执行,没有退出,Why? 这是因为:

「注意:发生异常时线程的中断标志为会由true更改为false。」

所以最好这样写成这样:

// 模拟重复执行的任务
				while (!Thread.currentThread().isInterrupted()) {
					System.out.println("doSomething");
					
					// 模拟阻塞 500ms
					try {
						Thread.currentThread().sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
						// 重置中断标志位为true
	                    Thread.currentThread().interrupt();
					}
				}

在出现异常后,重置中断标志位,这样再次执行后,就可以顺利中断线程了:

image-20221209153306915

当然也可以在出现异常时,直接使用return语句终止,那样也是可以的,今天在是review一个同事的code时发现了此问题,所以记录一下。

参考链接:

为什么说volatile+interrupt是停止线程最优雅的姿势?



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   夜行过客  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
历史上的今天:
2019-12-09 Fragment: 使用newInstance()来实例化fragment(转)
2019-12-09 Java: 线程池(ThreadPoolExecutor)中的参数说明
点击右上角即可分享
微信分享提示