Thread的中断机制(interrupt)

调用Thread.interrupt()方法并不能真正停止线程,只是在当前线程做了一个中断的状态标志。

public class MyThread extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            super.run();
            System.out.println("i="+(i+1));
        }
    }

}
public class Runner {
    public static void main(String[] args) {

            MyThread myThread = new MyThread();
            myThread.start();
            myThread.interrupt();
            System.out.println("第一次调用myThread.isInterrupted(),返回值:"+myThread.isInterrupted());
            System.out.println("第二次调用myThread.isInterrupted(),返回值:"+myThread.isInterrupted());
            System.out.println("===========end=============");
    }

}

上面我们创建了一个MyThread线程,然后Runner类中,执行main方法,创建MyThread的实例,启动线程,然后调用myThread.interrupt(); 
打印出信息:

i=1 
第一次调用myThread.isInterrupted(),返回值:true 
i=2 
第二次调用myThread.isInterrupted(),返回值:true 
i=3 
==========end============== 
i=4 
i=5 
i=6 
i=7 
i=8 
i=9 
i=10 
i=11 
i=12 
i=13 
i=14

从打印信息可以看出,虽然调用了myThread.interrupt()方法,但是MyThread并没有立即中断执行。这里我们两次调用myThread.isInterrupted(),返回值都是true。 
我们对Runner方法坐下修改,改成两次调用myThread.interrupted()。 
代码如下:

public class Runner {
    public static void main(String[] args) {

            MyThread myThread = new MyThread();
            myThread.start();
            myThread.interrupt();
            System.out.println("第一次调用myThread.interrupted(),返回值:"+myThread.interrupted());
            System.out.println("第二次调用myThread.interrupted(),返回值:"+myThread.interrupted());
            System.out.println("============end===================");
    }

}

打印信息如下:

第一次调用myThread.interrupted(),返回值:false 
i=1 
第二次调用myThread.interrupted(),返回值:false 
i=2 
===========end================= 
i=3 
i=4 
i=5 
i=6

虽然线程依然没有被中断,但是调用myThread.interrupted()是,返回都是false。难度是MyThread并没有中断状态吗?

再看一下代码:

public class Runner {
    public static void main(String[] args) {

            Thread.currentThread().interrupt();
            System.out.println("第一次调用Thread.interrupted(),返回值:"+Thread.interrupted());
            System.out.println("第二次调用Thread.interrupted(),返回值:"+Thread.interrupted());
            System.out.println("=================end===============================");
    }

}

打印信息如下:

第一次调用Thread.interrupted(),返回值:true 
第二次调用Thread.interrupted(),返回值:false 
========end=======

以上代码是对当前线程,即main方法执行的线程,调用interrupt方法。第一次调用Thread.interrupted()返回值是true,说明当前线程已经被标记了中断状态,那么为什么第二次调用Thread.interrupted()返回值却是false呢?

这里需要引出官方文档对Thread.interrupted()的定义:

测试当前线程是否已经中断,线程的中断状态也是由该方法清除。

也就是说,如果连续两次调用该方法,那么第一次调用时,如果当前线程已经处于中断状态,那么该方法会返回true,同时清除当前线程被标记的中断状态。第二次调用时,(第二次调用之前,没有再次调用Thread.currentThread().interrupt();)就会返回false了。

总结

  1. 调用线程的interrupt方法,并不能真正中断线程,只是给线程做了中断状态的标志
  2. Thread.interrupted():测试当前线程是否处于中断状态。执行后将中断状态标志为false
  3. Thread.isInterrupted(): 测试线程Thread对象是否已经处于中断状态。但不具有清除功能

 中断线程 —— interrupt() 

 一个正在运行的线程除了正常的时间片中断之外,能否被其他线程控制?或者说其他线程能否让指定线程放弃CPU或者提前结束运行? 除了线程同步机制之外,还有两种方法:
       (1) Thread.stop(), Thread.suspend(), Thread.resume() 和Runtime.runFinalizersOnExit() 这些终止线程运行的方法 。这些方法已经被废弃,使用它们是极端不安全的。
       (2) Thread.interrupt() 方法是很好的选择。但是使用的时候我们必须好好理解一下它的用处。

[java]  view plain  copy
  1. //无法中断正在运行的线程代码    
  2. class TestRunnable implements Runnable{    
  3.       public void run(){    
  4.             while(true)    
  5.             {    
  6.                   System.out.println( "Thread is running..." );    
  7.                   long time = System.currentTimeMillis();//去系统时间的毫秒数    
  8.             while((System.currentTimeMillis()-time < 1000)) {    
  9.                    //程序循环1秒钟,不同于sleep(1000)会阻塞进程。    
  10.             }    
  11.               }    
  12.        }    
  13. }    
  14. public class ThreadDemo{    
  15.          public static void main(String[] args){    
  16.                Runnable r=new TestRunnable();    
  17.                Thread th1=new Thread(r);    
  18.                th1.start();    
  19.                th1.interrupt();             
  20.         }    
  21. }    
  22. /运行结果:一秒钟打印一次Thread is running...。程序没有终止的任何迹象   

上面的代码说明interrupt()并没有中断一个正在运行的线程,或者说让一个running中的线程放弃CPU。那么interrupt到底中断什么。
       首先我们看看interrupt究竟在干什么。
       当我们调用th1.interrput()的时候,线程th1的中断状态(interrupted status) 会被置位。我们可以通过Thread.currentThread().isInterrupted() 来检查这个布尔型的中断状态。
        在Core Java中有这样一句话:"没有任何语言方面的需求要求一个被中断的程序应该终止。中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断 "。好好体会这句话的含义,看看下面的代码:

[java]  view plain  copy
  1. //Interrupted的经典使用代码    
  2. public void run(){    
  3.         try{    
  4.              ....    
  5.              while(!Thread.currentThread().isInterrupted()&& more work to do){    
  6.                     // do more work;    
  7.              }    
  8.         }catch(InterruptedException e){    
  9.                     // thread was interrupted during sleep or wait    
  10.         }    
  11.         finally{    
  12.                    // cleanup, if required    
  13.         }    
  14. }    

很显然,在上面代码中,while循环有一个决定因素就是需要不停的检查自己的中断状态。当外部线程调用该线程的interrupt 时,使得中断状态置位。这是该线程将终止循环,不在执行循环中的do more work了。

       这说明: interrupt中断的是线程的某一部分业务逻辑,前提是线程需要检查自己的中断状态(isInterrupted())。

       但是当th1被阻塞的时候,比如被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞时。调用它的interrput()方法。可想而知,没有占用CPU运行的线程是不可能给自己的中断状态置位的。这就会产生一个InterruptedException异常。

[java]  view plain  copy
  1.  //中断一个被阻塞的线程代码  
  2. class TestRunnable implements Runnable{  
  3.      public void run(){  
  4.           try{  
  5.         Thread.sleep(1000000); //这个线程将被阻塞1000秒  
  6.        }catch(InterruptedException e){  
  7.          e.printStackTrace();  
  8.                      //do more work and return.  
  9.           }  
  10.      }  
  11. }  
  12. public class TestDemo2{  
  13.       public static void main(String[] args) {  
  14.             Runnable tr=new TestRunnable();  
  15.             Thread th1=new Thread(tr);  
  16.             th1.start(); //开始执行分线程  
  17.         while(true){  
  18.        th1.interrupt();  //中断这个分线程  
  19.         }  
  20.       }  
  21. }  
  22. /*运行结果: 
  23.    java.lang.InterruptedException: sleep interrupted 
  24.         at java.lang.Thread.sleep(Native Method) 
  25.         at TestRunnable.run(TestDemo2.java:4) 
  26.         at java.lang.Thread.run(Unknown Source)*/  

* 如果线程被阻塞,它便不能核查共享变量,也就不能停止。这在许多情况下会发生,例如调用
* Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时,他们都可能永
* 久的阻塞线程。即使发生超时,在超时期满之前持续等待也是不可行和不适当的,所以,要使
* 用某种机制使得线程更早地退出被阻塞的状态。很不幸运,不存在这样一种机制对所有的情况
* 都适用,但是,根据情况不同却可以使用特定的技术。使用Thread.interrupt()中断线程正
* 如Example1中所描述的,Thread.interrupt()方法不会中断一个正在运行的线程。这一方法
* 实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更
* 确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,
* 它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值