(一).关于interrupt()
    interrupt()并不直接中断线程,而是设定一个中断标识,然后由程序进行中断检查,确定是否中断。
    1. sleep() & interrupt()
    线程A正在使用sleep()暂停着: Thread.sleep(100000);
    如果要取消他的等待状态,可以在正在执行的线程里(比如这里是B)调用a.interrupt();
    令线程A放弃睡眠操作,这里a是线程A对应到的Thread实例执行interrupt()时,并不需要获取Thread实例的锁定.任何线程在任何时刻,都可以调用其他线程interrupt().当sleep中的线程被调用interrupt()时,就会放弃暂停的状态.并抛出InterruptedException.丢出异常的,是A线程.
2. wait() & interrupt()
    线程A调用了wait()进入了等待状态,也可以用interrupt()取消.
    不过这时候要小心锁定的问题.线程在进入等待区,会把锁定解除,当对等待中的线程调用interrupt()时(注意是等待的线程调用其自己的interrupt()),会先重新获取锁定,再抛出异常.在获取锁定之前,是无法抛出异常的.
3. join() & interrupt()
    当线程以join()等待其他线程结束时,一样可以使用interrupt()取消之.因为调用join()不需要获取锁定,故与sleep()时一样,会马上跳到catch块里. 注意是随调用interrupt()方法,一定是阻塞的线程来调用其自己的interrupt方法.如在线程a中调用来线程t.join().则a会等t执行完后在执行t.join后的代码,当在线程b中调用来a.interrupt()方法,则会抛出InterruptedException
4. interrupt()只是改变中断状态而已
    interrupt()不会中断一个正在运行的线程。这一方法实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。
    如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就将得到异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。
    线程A在执行sleep,wait,join时,线程B调用A的interrupt方法,的确这一个时候A会有InterruptedException异常抛出来.但这其实是在sleep,wait,join这些方法内部会不断检查中断状态的值,而自己抛出的InterruptedException。
    如果线程A正在执行一些指定的操作时如赋值,for,while,if,调用方法等,都不会去检查中断状态,所以线程A不会抛出InterruptedException,而会一直执行着自己的操作.当线程A终于执行到wait(),sleep(),join()时,才马上会抛出InterruptedException.
    若没有调用sleep(),wait(),join()这些方法,或是没有在线程里自己检查中断状态自己抛出InterruptedException的话,那InterruptedException是不会被抛出来的.   
 
(二)Java线程中断的本质和编程原则
    在历史上,Java试图提供过抢占式限制中断,但问题多多,例如前文介绍的已被废弃的Thread.stop、Thread.suspend和 Thread.resume等。另一方面,出于Java应用代码的健壮性的考虑,降低了编程门槛,减少不清楚底层机制的程序员无意破坏系统的概率。
    如今,Java的线程调度不提供抢占式中断,而采用协作式的中断。其实,协作式的中断,原理很简单,就是轮询某个表示中断的标记,我们在任何普通代码的中都可以实现。 例如下面的代码:
    volatile bool isInterrupted;
    //…
    while(!isInterrupted) {
        compute();
    }
    但是,上述的代码问题也很明显。当compute执行时间比较长时,中断无法及时被响应。另一方面,利用轮询检查标志变量的方式,想要中断wait和sleep等线程阻塞操作也束手无策。
    如果仍然利用上面的思路,要想让中断及时被响应,必须在虚拟机底层进行线程调度的对标记变量进行检查。是的,JVM中确实是这样做的。下面摘自java.lang.Thread的源代码:
        public static boolean interrupted() {
            return currentThread().isInterrupted(true);
        }
       //…
        private native boolean isInterrupted(boolean ClearInterrupted);
    可以发现,isInterrupted被声明为native方法,取决于JVM底层的实现。
    实际上,JVM内部确实为每个线程维护了一个中断标记。但应用程序不能直接访问这个中断变量,必须通过下面几个方法进行操作:
    public class Thread {
        //设置中断标记
        public void interrupt() { ... } 
        //获取中断标记的值
        public boolean isInterrupted() { ... }
        //清除中断标记,并返回上一次中断标记的值
        public static boolean interrupted() { ... }  
        ...
    }
    通常情况下,调用线程的interrupt方法,并不能立即引发中断,只是设置了JVM内部的中断标记。因此,通过检查中断标记,应用程序可以做一些特殊操作,也可以完全忽略中断。
    你可能想,如果JVM只提供了这种简陋的中断机制,那和应用程序自己定义中断变量并轮询的方法相比,基本也没有什么优势。
    JVM内部中断变量的主要优势,就是对于某些情况,提供了模拟自动“中断陷入”的机制。
    在执行涉及线程调度的阻塞调用时(例如wait、sleep和join),如果发生中断,被阻塞线程会“尽可能快的”抛出InterruptedException。因此,我们就可以用下面的代码框架来处理线程阻塞中断:
    try {
        //wait、sleep或join
       }
    catch(InterruptedException e) {
        //某些中断处理工作 
      }
    所谓“尽可能快”,我猜测JVM就是在线程调度调度的间隙检查中断变量,速度取决于JVM的实现和硬件的性能。   
    然而,对于某些线程阻塞操作,JVM并不会自动抛出InterruptedException异常。例如,某些I/O操作和内部锁操作。对于这类操作,可以用其他方式模拟中断:
    1)java.io中的异步socket I/O
    读写socket的时候,InputStream和OutputStream的read和write方法会阻塞等待,但不会响应java中断。不过,调用Socket的close方法后,被阻塞线程会抛出SocketException异常。
    2)利用Selector实现的异步I/O
    如果线程被阻塞于Selector.select(在java.nio.channels中),调用wakeup方法会引起ClosedSelectorException异常。
    3)锁获取
    如果线程在等待获取一个内部锁,我们将无法中断它。但是,利用Lock类的lockInterruptibly方法,我们可以在等待锁的同时,提供中断能力。
    另外,在任务与线程分离的框架中,任务通常并不知道自身会被哪个线程调用,也就不知道调用线程处理中断的策略。所以,在任务设置了线程中断标记后,并不能确保任务会被取消。因此,有以下两条编程原则:
    1)除非你知道线程的中断策略,否则不应该中断它。
        这条原则告诉我们,不应该直接调用Executer之类框架中线程的interrupt方法,应该利用诸如Future.cancel的方法来取消任务。
    2)任务代码不该猜测中断对执行线程的含义。
        这条原则告诉我们,一般代码遇在到InterruptedException异常时,不应该将其捕获后“吞掉”,而应该继续向上层代码抛出。
    总之,Java中的非抢占式中断机制,要求我们必须改变传统的抢占式中断思路,在理解其本质的基础上,采用相应的原则和模式来编程。
 
(三) interrupt() 与 cancel()的区别
   两者实际上都是中断线程,但是后者更安全、有条理和高效,其原因跟推荐使用Executor而不直接使用Thread类是一致的。所以结合上面讲到的原则,我们应尽量采用cancel()方法,调用线程管理器ExecutorService接口的submit(Runnable task) 方法会返回一个Future<?>对象,然后调用Future.cancel()的方法来取消任务,并返回一个boolean值。

【Future】

http://www.gznc.edu.cn/yxsz/jjglxy/book/Java_api/java/util/concurrent/Future.html

【好奇】

(1)future.cancel(mayInterruptIfRunning)的内部实现会是什么样子的?可以中断一个线程池里正在执行着的“那一个”任务。

可猜想,必定记录着具体线程标识,且发了一个中断信号。

(2)猜测,应该只是发一个中断信号,可以中断阻塞中的操作。而如果是while(true); 这样的占用CPU的非阻塞式操作,是中断不掉的,也即线程依旧在跑,占用着线程池资源。

【注意】

a). 线程池资源有限,有些任务会submit()不进去,抛异常:java.util.concurrent.RejectedExecutionException

b).只要submit()成功的,无论是线程正在执行,或是在BlockingQueue中等待执行,future.cancel()操作均可中断掉线程。也即,与其真正执行并无关系,阻塞中或等待被调度执行中,都将被中断。

【demo示例】

future.cancel中断阻塞操作:

public class Main {
    
    /** 信号量 */
    private Semaphore semaphore = new Semaphore(0); // 1
    
    /** 线程池 */
    private ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 5, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3));
    
    /** Future */
    private Future<String> future ;
    
    public void test(){
        
        future = pool.submit(new Callable<String>() {
 
            @Override
            public String call() {
                String result = null;
                try {
                    // 同步阻塞获取信号量
                    semaphore.acquire();
                    result = "ok";
                } catch (InterruptedException e) {
                    result = "interrupted";
                }
                return result;
            }
        });
        
        String result = "timeout";
        try {
            // 等待3s
            result = future.get(3, TimeUnit.SECONDS);
        }catch (Exception e) {
            System.out.println("超时异常");
        }
        
        // 删除线程池中任务
        boolean cancelResult = future.cancel(true);
        
        System.out.println("result is " + result);
        System.out.println("删除结果:"  +cancelResult);
        System.out.println("当前active线程数:" +pool.getActiveCount());
        
    }
 
    public static void main(String[] args) {
        Main o = new Main();        
        o.test();
    }
}

http://www.cnblogs.com/alipayhutu/archive/2012/06/20/2556091.html

http://blog.sina.com.cn/s/blog_00ccd2400100nq7o.html

线程中断方法interrupt() 与 cancel()的更多相关文章

  1. 从头认识java-17.2 线程中断(interrupt)

    这一章节我们来讨论一下线程中断(interrupt). 1.什么是线程中断(interrupt)? 就是在多线程执行的时候,我们给线程贴上一个中断的标记.可是不要求线程终止. 2.样例: 中断的样例: ...

  2. 日积月累--线程中断interrupt()方法

    线程中断方法interrupt()方法的理解: interrupt()方法的源码: interrupted()方法的源码及注解: isInterrupted()方法源码及注解: 在了解这个方法之前我们 ...

  3. java 线程的终止与线程中断

    关于线程终止: 1.一般来讲线程在执行完毕后就会进入死亡状态,那该线程自然就终止了. 2.一些服务端的程序,可能在业务上需要,常驻系统.它本身是一个无穷的循环,用于提供服务.那对于这种线程我们该如何结 ...

  4. Thread线程中断相关方法

    public class Demo { /* * 线程中断相关方法 * ---------------------------------------------------------------- ...

  5. 【Java并发编程】之二:线程中断

    [Java并发编程]之二:线程中断 使用interrupt()中断线程 ​ 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一 ...

  6. 线程中断:Thread类中interrupt()、interrupted()和 isInterrupted()方法详解

    首先看看官方说明: interrupt()方法 其作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行. i ...

  7. java线程中的interrupt,isInterrupt,interrupted方法

    在java的线程Thread类中有三个方法,比较容易混淆,在这里解释一下 (1)interrupt:置线程的中断状态 (2)isInterrupt:线程是否中断 (3)interrupted:返回线程 ...

  8. Java中的线程Thread方法之---interrupt()

    前几篇都介绍了Thread中的几个方法,相信大家都发现一个相似点,那就是sleep,join,wait这样的阻塞方法都必须捕获一个InterruptedException异常,顾名思义就是一个线程中断 ...

  9. 停止Java线程,小心interrupt()方法

    来源:http://blog.csdn.net/wxwzy738/article/details/8516253 程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决 ...

随机推荐

  1. 【大数据之数据仓库】GreenPlum优化器对比测试

    在< [大数据之数据仓库]选型流水记>一文中有提及,当时没有测试GreenPlum的quicklz压缩算法和ORCA查询优化器,考虑到quicklz压缩算法因为版权问题不会开源(详情请参阅 ...

  2. 20165219 学习基础与C语言基础调查

    学习基础与C语言基础调查 你有什么技能比大多数人要好? 因为不知道其他人的具体情况,我只能说,我比较擅长钢琴,素描,国画,这也是小时候掌握的比较好的技能. 针对这个技能的获取有什么成功的经验 小时候学 ...

  3. Java中的Date Time 与SQL Server 2005里的Datetime 之间的交互

    Preface Environment:Platform: Windows XPLanguage: Java 1.5IDE: MyEclipse 6.0.1Database: SQL Server 2 ...

  4. 5、用Numpy实现结构体

    1.结构数组: 在C语言中我们可以通过struct关键字定义结构类型,结构中的字段占据连续的内存空间,每个结构体占用的内存大小都相同,因此可以很容易地定义结构数组.和C语言一样,在NumPy中也很容易 ...

  5. 如何在JAVA中每隔一段时间执行一段程序

    可以用线程来做,每隔几秒开一个线程代码如下 public void runTask() { final long timeInterval = 120000;// 两分钟运行一次 final Thre ...

  6. Asp.Net 远程连接Oracle数据库

    Asp.Net 远程连接Oracle数据库 首先从微软停止.Net FrameWork支持Oracle数据库的研发,转为第三方提供说起,微软是很有实力的公司,他在桌面领域令其他对手望其项背,产品战线也 ...

  7. java8 方法引用与lambda

    List<String> list = new ArrayList<>(); //list.stream().filter((String s)->System.out. ...

  8. springboot(一):入门

    什么是springboot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不 ...

  9. Web Worker 案例

    什么是 Web Worker? 当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成. web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性 ...

  10. Hyda爆破

    转载:http://www.cnblogs.com/bmjoker/ 2018,网站的防护(sql,xss...)的安全保护也已经上升了一个等级,但是由于管理员的安全意识薄弱,网站弱口令漏洞依然猖獗, ...