网站首页 > 技术教程 正文
我们都知道,Java中停止一个线程不能用stop,因为stop会瞬间强行停止一个线程,且该线程持有的锁并不能释放。大家多习惯于用interrupt,那么使用它又有什么需要注意的呢?
interrupt相关的方法
Java中和interrupt相关的方法有三个
public boolean isInterrupted() public void interrupt() public static boolean interrupted()
boolean isInterrupted()
每个线程都一个状态位用于标识当前线程对象是否是中断状态。isInterrupted主要用于判断当前线程对象的中断标志位是否被标记了,如果被标记了则返回true,表示当前已经被中断,否则返回false。我们也可以看看它的实现源码:
public boolean isInterrupted() { return isInterrupted(false); } private native boolean isInterrupted(boolean ClearInterrupted);
底层调用的native方法isInterrupted,传入一个boolean类型的参数,用于指定调用该方法之后是否需要清除该线程的中断标识位。从这里我们也可以看出来,调用isInterrupted()并不会清除线程的中断标识位。
void interrupt()
interrupt()用于设置当前线程对象的中断标识位,其源码为:
public void interrupt() { // 检查当前线程是否有权限修改目标线程,如果没有,则会抛出异常SecurityException if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); // Just to set the interrupt flag b.interrupt(this); return; } } interrupt0(); }
blockerLock和blocker都和阻塞IO时产生的中断相关,因此推测interrupt()需要当阻塞IO操作执行完之后,才可以执行。
interrupt()其实只是改变了一个标志位,对于线程本身的状态并没有影响。
boolean interrupted()
该方法是一个静态的方法,用于返回当前线程是否被中断,其源码是:
public static boolean interrupted() { return currentThread().isInterrupted(true); }
需要注意的是:该方法调用结束的时候会清空中断标识位。
线程的状态与中断的关系
我们知道,Java中的线程一共6种状态,分别是NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED(Thread类中有一个State枚举类型列举了线程的所有状态)。下面我们就将把线程分别置于上述的不同种状态,然后看看中断操作对它们的影响。
NEW和TERMINATED
NEW状态表示线程还未调用start()方法,TERMINATED状态表示线程已经运行终止。
这两个状态下调用中断方法来中断线程的时候,Java认为毫无意义,所以并不会设置线程的中断标识位。例如:
NEW状态:
public static void main(String[] args) { Thread thread = new Thread(); System.out.println(thread.getState()); System.out.println(thread.isInterrupted()); thread.interrupt(); System.out.println(thread.isInterrupted()); }
输出结果:
NEW false false
TERMINATED状态:
public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(); // 开始线程 thread.start(); // 等待线程结束 thread.join(); System.out.println(thread.getState()); System.out.println(thread.isInterrupted()); thread.interrupt(); System.out.println(thread.isInterrupted()); }
输出结果:
TERMINATED false false
从上述的两个例子来看,处于NEW和TERMINATED状态的线程,对于中断是屏蔽的,也就是说中断操作对这两种状态下的线程是无效的。
RUNNABLE
处于RUNNABLE状态的线程,当中断线程后,会修改其中断标志位,但并不会影响线程本身。例如:
/** * 自定义线程类 */ public class MyThread extends Thread{ @Override public void run(){ while(true){ // 什么都不做,就是空转 } } public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); System.out.println(thread.getState()); System.out.println(thread.isInterrupted()); thread.interrupt(); System.out.println(thread.isInterrupted()); System.out.println(thread.getState()); } }
结果为:
RUNNABLE false true RUNNABLE
中断标志位确实被改变了,但线程依旧继续运行。那我们调用interrupt()方法的意义在哪儿?
其实Java是将中断线程的权利交给了我们自己的程序,通过中断标志位,我们的程序可以通过boolean isInterrupted()方法来判断当前线程是否中断,从而决定之后的操作。
我们可以在此基础上,保证执行任务的原子性。例如修改MyThread类的方法:
/** * 自定义线程类 */ public class MyThread extends Thread{ @Override public void run(){ while(true){ if (this.isInterrupted()){ System.out.println("exit MyThread"); break; } } } public static void main(String[] args) throws InterruptedException { Thread thread = new MyThread(); thread.start(); System.out.println(thread.getState()); System.out.println(thread.isInterrupted()); thread.interrupt(); System.out.println(thread.isInterrupted()); thread.join(); System.out.println(thread.getState()); } }
结果为:
RUNNABLE false true exit MyThread TERMINATED
BLOCKED
当线程处于BLOCKED状态,说明该线程由于竞争某个对象的锁失败而被挂在了该对象的阻塞队列上了。
那么此时发起中断操作不会对该线程产生任何影响,依然只是设置中断标志位。例如:
/** * 自定义线程类 */ public class MyThread extends Thread{ public synchronized static void doSomething(){ while(true){ // 空转 } } @Override public void run(){ doSomething(); } public static void main(String[] args) throws InterruptedException { // 启动两个线程 Thread thread1 = new MyThread(); thread1.start(); Thread thread2 = new MyThread(); thread2.start(); Thread.sleep(1000); System.out.println(thread1.getState()); System.out.println(thread2.getState()); System.out.println(thread2.isInterrupted()); thread2.interrupt(); System.out.println(thread2.isInterrupted()); System.out.println(thread2.getState()); } }
结果为:
RUNNABLE BLOCKED false true BLOCKED
thread2处于BLOCKED状态,执行中断操作之后,该线程仍然处于BLOCKED状态,但是中断标志位却已被修改。
这种状态下的线程和处于RUNNABLE状态下的线程是类似的,给了我们程序更大的灵活性去判断和处理中断。
WAITING/TIMED_WAITING
这两种状态本质上是同一种状态,只不过TIMED_WAITING在等待一段时间后会自动释放自己,而WAITING则是无限期等待,需要其他线程调用类似notify方法释放自己。但是他们都是线程在运行的过程中由于缺少某些条件而被挂起在某个对象的等待队列上。
当这些线程遇到中断操作的时候,会抛出一个InterruptedException异常,并清空中断标志位。例如:
/** * 自定义线程类 */ public class MyThread extends Thread{ @Override public void run(){ synchronized (this){ try { wait(); } catch (InterruptedException e) { System.out.println("catch InterruptedException"); } } } public static void main(String[] args) throws InterruptedException { Thread thread = new MyThread(); thread.start(); Thread.sleep(1000); System.out.println(thread.getState()); System.out.println(thread.isInterrupted()); thread.interrupt(); Thread.sleep(1000); System.out.println(thread.isInterrupted()); } }
结果为:
WAITING false catch InterruptedException false
从运行结果看,当线程启动之后就被挂起到该线程对象的等待队列上,然后我们调用interrupt()方法对该线程进行中断,输出了我们在catch中的输出语句,显然是捕获了InterruptedException异常,接着就看到该线程的中断标志位被清空。
因此我们要么就在catch语句中结束线程,否则就在catch语句中加上this.interrupt();,再次设置标志位,这样也方便在之后的逻辑或者其他地方继续判断。
总结
我们介绍了线程在不同状态下对于中断请求的反应:
- NEW和TERMINATED对于中断操作几乎是屏蔽的。
- RUNNABLE和BLOCKED类似,对于中断操作只是设置中断标志位并没有强制终止线程,对于线程的终止权利依然在程序手中。
- WAITING和TIMED_WAITING状态下的线程对于中断操作是敏感的,他们会抛出异常并清空中断标志位。
有兴趣的话可以关注我的公众号或者头条号,说不定会有意外的惊喜。
猜你喜欢
- 2024-10-30 Thread生命周期及interrupted()作用分析
- 2024-10-30 java 是怎么中断一个线程的,你真的搞懂了吗?interrupt()
- 2024-10-30 java中interrupt,interrupted和isInterrupted的区别
- 2024-10-30 说一下interrupt()、interrupted()和isInterrupted()的区别
- 2024-10-30 「浅谈Java」2,interrupt,interrupted和isInterrupted的区别
- 2024-10-30 线程的正确终止:interrupt(线程中断的几种 方式)
你 发表评论:
欢迎- 最近发表
-
- linux CentOS检查见后门程序的shell
- 网络安全工程师演示:黑客是如何使用Nmap网络扫描工具的?
- Linux中ftp服务修改默认21端口等(linux修改ftp配置文件)
- Linux系统下使用Iptables配置端口转发,运维实战收藏!
- 谈谈TCP和UDP源端口的确定(tcp和udp的端口号相同吗)
- Linux 系统 通过端口号找到对应的服务及相应安装位置
- 快速查找NAS未占用端口!Docker端口秒级排查+可视化占坑双杀技
- 【知识杂谈#2】如何查看Linux的(本地与公网)IP地址与SSH端口号
- 如何在Linux中查询 DNS 记录,这三个命令可谓是最常用、最经典的
- 【Linux系统编程】特殊进程之守护进程
- 标签列表
-
- 下划线是什么 (87)
- 精美网站 (58)
- qq登录界面 (90)
- nginx 命令 (82)
- nginx .http (73)
- nginx lua (70)
- nginx 重定向 (68)
- Nginx超时 (65)
- nginx 监控 (57)
- odbc (59)
- rar密码破解工具 (62)
- annotation (71)
- 红黑树 (57)
- 智力题 (62)
- php空间申请 (61)
- 按键精灵 注册码 (69)
- 软件测试报告 (59)
- ntcreatefile (64)
- 闪动文字 (56)
- guid (66)
- abap (63)
- mpeg 2 (65)
- column (63)
- dreamweaver教程 (57)
- excel行列转换 (56)
本文暂时没有评论,来添加一个吧(●'◡'●)