用interrupt()中断Java线程

最近在学习Java线程相关的东西,和大家分享一下,有错误之处欢迎大家指正.

假如我们有一个任务如下,交给一个Java线程来执行,如何才能保证调用interrupt()来中断它呢?

Java代码  

  1. class ATask implements Runnable{
  2. private double d = 0.0;
  3. public void run() {
  4. //死循环执行打印"I am running!" 和做消耗时间的浮点计算
  5. while (true) {
  6. System.out.println("I am running!");
  7. for (int i = 0; i < 900000; i++) {
  8. d =  d + (Math.PI + Math.E) / d;
  9. }
  10. //给线程调度器可以切换到其它进程的信号
  11. Thread.yield();
  12. }
  13. }
  14. }
  15. public class InterruptTaskTest {
  16. public static void main(String[] args) throws Exception{
  17. //将任务交给一个线程执行
  18. Thread t = new Thread(new ATask());
  19. t.start();
  20. //运行一断时间中断线程
  21. Thread.sleep(100);
  22. System.out.println("****************************");
  23. System.out.println("Interrupted Thread!");
  24. System.out.println("****************************");
  25. t.interrupt();
  26. }
  27. }

运行这个程序,我们发现调用interrupt()后,程序仍在运行,如果不强制结束,程序将一直运行下去,如下所示:

Java代码  

  1. ......
  2. I am running!
  3. I am running!
  4. I am running!
  5. I am running!
  6. ****************************
  7. Interrupted Thread!
  8. ****************************
  9. I am running!
  10. I am running!
  11. I am running!
  12. I am running!
  13. I am running!
  14. ....

虽然中断发生了,但线程仍然在进行,离开线程有两种常用的方法: 
抛出InterruptedException和用Thread.interrupted()检查是否发生中断,下面分别看一下这两种方法: 
1.在阻塞操作时如Thread.sleep()时被中断会抛出InterruptedException(注意,进行不能中断的IO操作而阻塞和要获得对象的锁调用对象的synchronized方法而阻塞时不会抛出InterruptedException)

Java代码  

  1. class ATask implements Runnable{
  2. private double d = 0.0;
  3. public void run() {
  4. //死循环执行打印"I am running!" 和做消耗时间的浮点计算
  5. try {
  6. while (true) {
  7. System.out.println("I am running!");
  8. for (int i = 0; i < 900000; i++) {
  9. d =  d + (Math.PI + Math.E) / d;
  10. }
  11. //休眠一断时间,中断时会抛出InterruptedException
  12. Thread.sleep(50);
  13. }
  14. } catch (InterruptedException e) {
  15. System.out.println("ATask.run() interrupted!");
  16. }
  17. }
  18. }

程序运行结果如下:

Java代码  

  1. I am running!
  2. I am running!
  3. ****************************
  4. Interrupted Thread!
  5. ****************************
  6. ATask.run() interrupted!

可以看到中断任务时让任务抛出InterruptedException来离开任务.

2.Thread.interrupted()检查是否发生中断.Thread.interrupted()能告诉你线程是否发生中断,并将清除中断状态标记,所以程序不会两次通知你线程发生了中断.

Java代码  

  1. class ATask implements Runnable{
  2. private double d = 0.0;
  3. public void run() {
  4. //检查程序是否发生中断
  5. while (!Thread.interrupted()) {
  6. System.out.println("I am running!");
  7. for (int i = 0; i < 900000; i++) {
  8. d = d + (Math.PI + Math.E) / d;
  9. }
  10. }
  11. System.out.println("ATask.run() interrupted!");
  12. }
  13. }

程序运行结果如下:

Java代码  

  1. I am running!
  2. I am running!
  3. I am running!
  4. I am running!
  5. I am running!
  6. I am running!
  7. I am running!
  8. ****************************
  9. Interrupted Thread!
  10. ****************************
  11. ATask.run() interrupted!

我们可结合使用两种方法来达到可以通过interrupt()中断线程.请看下面例子:

Java代码  

  1. class ATask implements Runnable{
  2. private double d = 0.0;
  3. public void run() {
  4. try {
  5. //检查程序是否发生中断
  6. while (!Thread.interrupted()) {
  7. System.out.println("I am running!");
  8. //point1 before sleep
  9. Thread.sleep(20);
  10. //point2 after sleep
  11. System.out.println("Calculating");
  12. for (int i = 0; i < 900000; i++) {
  13. d = d + (Math.PI + Math.E) / d;
  14. }
  15. }
  16. } catch (InterruptedException e) {
  17. System.out.println("Exiting by Exception");
  18. }
  19. System.out.println("ATask.run() interrupted!");
  20. }
  21. }

在point1之前处point2之后发生中断会产生两种不同的结果,可以通过修改InterruptTaskTest main()里的Thread.sleep()的时间来达到在point1之前产生中断或在point2之后产生中断. 
如果在point1之前发生中断,程序会在调用Thread.sleep()时抛出InterruptedException从而结束线程.这和在Thread.sleep()时被中断是一样的效果.程序运行结果可能如下:

Java代码  

  1. I am running!
  2. Calculating
  3. I am running!
  4. Calculating
  5. I am running!
  6. Calculating
  7. I am running!
  8. ****************************
  9. Interrupted Thread!
  10. ****************************
  11. Exiting by Exception
  12. ATask.run() interrupted!

如果在point2之后发生中断,线程会继续执行到下一次while判断中断状态时.程序运行结果可能如下:

Java代码  

  1. I am running!
  2. Calculating
  3. I am running!
  4. Calculating
  5. I am running!
  6. Calculating
  7. ****************************
  8. Interrupted Thread!
  9. ****************************
  10. ATask.run() interrupted!

Java多线程中,线程的状态有 NEW, Runnable, Blocked, Waiting, Timed_Waiting, Terminated. 这是java虚拟机下的线程状态,与操作系统下的线程状态略有不同。线程状态以枚举类型定义在Thread.State中,并且当前线程可以通过getState()方法获取当前线程的状态。Runnable其实可以有两种状态,一种是获得了cpu,这在运行,这里把它表示为Running,另一种在队列中,等待调度。

这些状态之间的转化关系可以通过下面的转化图表示:

有些过程没有写,不然太乱了。

这里重点说一下stop()以及interrupt。

对于stop()方法,直接终止线程,释放线程所获的资源,但是在释放过程中会造成对象状态不一致,从而使程序进入未知的境地,已经很久不推荐使用了。可以通过设定标志位来检测线程终止状态,使线程自动终止。简略实现如下:

boolean stop = false;

public void run(){

while(!stop){

}

}

在需要终止线程的地方把stop设置为true即可。

interrupt方法好多初学者会感到困惑,发现一些情况下并不能终止线程。在JavaAPI中有对此详细的说明:

如果线程在调用 Object 类的 wait()wait(long) 或 wait(long, int) 方法,或者该类的join()join(long)join(long, int)sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException

如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException

因此,可以看出,interrupt之后作用到wait() join() 已经sleep()上。 2014阿里巴巴笔试题的附加题中对这个知识进行了终点考核,其代码如下:

[java] view plain copy

  1. public class TestInterrupt {
  2. /**
  3. * @param args
  4. */
  5. public static void main(String[] args) {
  6. // TODO Auto-generated method stub
  7. Thread thread1 = new Thread(){
  8. public void run(){
  9. try{
  10. long time = System.currentTimeMillis();
  11. while(System.currentTimeMillis()-time<2000){
  12. }
  13. System.out.println("A1");
  14. }
  15. catch(Exception e)
  16. {
  17. System.out.println("B1");
  18. }
  19. }
  20. };
  21. thread1.start();
  22. thread1.interrupt();
  23. //在线程sleep状态下进行中断
  24. Thread thread2 = new Thread(){
  25. public void run(){
  26. try {
  27. this.sleep(2000);
  28. System.out.println("A2");
  29. } catch (Exception e) {
  30. // TODO Auto-generated catch block
  31. System.out.println("B2");
  32. }
  33. }
  34. };
  35. thread2.start();
  36. thread2.interrupt();
  37. //在线程wait状态下进行中断,其中wait()没有在同步块中
  38. Thread thread3 = new Thread(){
  39. public void run(){
  40. try {
  41. this.wait(2000);
  42. System.out.println("A3");
  43. } catch (Exception e) {
  44. // TODO Auto-generated catch block
  45. System.out.println("B3");
  46. }
  47. }
  48. };
  49. thread3.start();
  50. thread3.interrupt();
  51. //在线程wait状态下进行中断,其中wait()在同步块中
  52. Thread thread4 = new Thread(){
  53. public void run(){
  54. try {
  55. synchronized(this){
  56. this.wait(2000);
  57. System.out.println("A4");}
  58. } catch (Exception e) {
  59. // TODO Auto-generated catch block
  60. System.out.println("B4");
  61. }
  62. }
  63. };
  64. thread4.start();
  65. thread4.interrupt();
  66. try{
  67. thread4.start();
  68. System.out.println("A5");
  69. }
  70. catch(Exception e)
  71. {
  72. System.out.println("B5");
  73. System.out.println(e.toString());
  74. }
  75. }
  76. }

我们可以运行,发下运行结果如下(不考虑执行顺序):

A1

B2

B3

B4

B5 //这个是由于一个thread,不能start两次引起的。。和interrupt无关

时间: 2024-12-10 11:00:30

用interrupt()中断Java线程的相关文章

如何中断JAVA线程

一些轻率的家伙可能被另一种方法Thread.interrupt所迷惑.尽管,其名称似乎在暗示着什么,然而,这种方法并不会中断一个正在运行的线程(待会将进一步说明),正如Listing A中描述的那样.它创建了一个线程,并且试图使用Thread.interrupt方法停止该线程.Thread.sleep()方法的调用,为线程的初始化和中止提供了充裕的时间.线程本身并不参与任何有用的操作. class Example1 extends Thread {             boolean sto

一文搞懂 Java 线程中断

在之前的一文<如何"优雅"地终止一个线程>中详细说明了 stop 终止线程的坏处及如何优雅地终止线程,那么还有别的可以终止线程的方法吗?答案是肯定的,它就是我们今天要分享的--线程中断. 下面的这断代码大家应该再熟悉不过了,线程休眠需要捕获或者抛出线程中断异常,也就是你在睡觉的时候突然有个人冲进来把你吵醒了. try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }

(4) java线程中断

使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即返回.这里需要注意的是,如果只是单纯的调用interrupt()方法,线程并没有实际被中断,会继续往下执行. public class InterruptTest { public static void main(String[] args) throws InterruptedException { M

java线程详细介绍

目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1

Java 线程宝典

此文 为垃圾文 本人复习用的 emmm 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程 并行与并发: 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时. 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时.并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力. 进程和线程的区分 第一种实现方式:通过继承Thread类来实现的 线程 摘要: code: package co

java 线程基本用法

java中的多线程 一.      java 线程基本介绍 1.进程与线程的区别 进程是指一个内存中运行的应用程序,每个进程都有一块独立的内存空间,一个进程包含一到多个线程. 每个线程都有他所属的进程,每个线程也就是该进程的一条执行路径,线程之间是高频率快速轮换执行的,‘同时’执行只是给人的感觉. 2.Java当中线程一般有5中状态 创建状态:生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态. 就绪状态:当调用了线程的start方法,线程就进入就绪状态,调用start方法后线

Thread的中断机制(interrupt),循环线程停止的方法

一.中断原理 中断线程 线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡.还是等待新的任务或是继续运行至下一步,就取决于这个程序本身.线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true).它并不像stop方法那样会中断一个正在运行的线程. 判断线程是否被中断 判断某个线程是否已被发送过中断请求,请使用Thread.currentThread().isInterrupted()方法(因为它将

线程中断、线程让步、线程睡眠、线程合并

线程中断 线程中断涉及到三个方法,如下: interrupt()方法用于中断线程,通常的理解来看,只要某个线程启动后,调用了该方法,则该线程不能继续执行了,来看个小例子: 运行后,我们发现,线程t一直在执行,没有被中断. 其实interrupt()方法并不是中断线程的执行,而是为调用该方法的线程对象打上一个标记,设置其中断状态为true,通过isInterrupted()方法可以得到这个线程状态,我们将上面的程序做一个小改动: class MyThread extends Thread{ int

java多线程技术: interrupt() 中断线程, 优雅停止线程及原理

MyThread.class package cn.yilong.edcsapiservice.thread; public class MyThread extends Thread { @Override public void run() { System.out.println("开始睡觉"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out