zoukankan      html  css  js  c++  java
  • java中断

    理解java中断

    Java中断机制是一种协作机制,即通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理中断。例如,当线程t1想中断线程t2,只需要在线程t1中将线程t2对象的中断标识置为true,然后线程2可以选择在合适的时候处理该中断请求,甚至可以不理会该请求,就像这个线程没有被中断一样。

    中断相关的方法:

    public class Thread{  
    public void interrupt(){}    //中断目标线程,实际上就是设置中断状态为true  
    public boolean isInterrupted(){} //返回目标线程的中断状态  
    public static boolean interrupted(){} //清除当前线程的中断状态,并返回它之前的值  
    } 
    

    非静态方法和静态方法的区别:

    //调用native方法,判断线程是否被中断,不清除中断状态
     public boolean isInterrupted() {
         return isInterrupted(false);
     }
      //调用native方法,判断线程是否被中断,清除中断状态
     public static boolean interrupted() {
         return currentThread().isInterrupted(true);
     }
    
      //native方法,测试线程是否被中断。ClearInterrupted决定是否需要清除中断状态
     private native boolean isInterrupted(boolean ClearInterrupted);
    

    JVM内部确实为每个线程维护了一个中断标记。但应用程序不能直接访问这个中断变量,必须通过上面几个方法进行操作。通常情况下,调用线程的interrupt方法,并不能立即引发中断,只是设置了JVM内部的中断标记。因此,通过检查中断标记,应用程序可以做一些特殊操作,也可以完全忽略中断。

    哪些场景可以用到中断?

    • 如果一个方法声明抛出InterruptedException,表示该方法是可中断的。比如sleep、wait、join等。
    //Thread类,native方法,当前线程休眠mills毫秒。如果其他线程中断当前线程,则当前线程抛出异常InterruptedException的时候清除当前线程的中断状态。   
      public static native void sleep(long millis) throws InterruptedException;
    
    //Object类  
    public final native void wait(long timeout) throws InterruptedException;
    public final native void notify();
    public final native void notifyAll();
    
    • 自定义的可中断方法。需要在适合处理中断的地方检测线程中断状态并处理。
    if(Thread.currentThread().isInterrupted()){
    	//do something
    }
    

    阻塞方法怎么响应中断

    • 对于自定义的可中断的方法,如上,在必要的时候,判断线程中断状态,来响应中断。当然,如果执行的时候,一直没有判断中断状态,自然也不会响应中断。
    • java封装的可中断方法,sleep等,是由JVM来控制的。

    一些不会抛出 InterruptedException 的线程阻塞操作

    然而,对于某些线程阻塞操作,JVM并不会自动抛出InterruptedException异常。例如,某些I/O操作和内部锁操作。对于这类操作,可以用其他方式模拟中断:

    • java.io中的同步IO
      读写socket的时候,InputStream和OutputStream的read和write方法会阻塞等待,但不会响应java中断。不过,调用Socket的close方法后,被阻塞线程会抛出SocketException异常。
    • 利用Selector实现的异步I/O
      如果线程被阻塞于Selector.select(在java.nio.channels中),调用wakeup方法会引起ClosedSelectorException异常。
    • 等待获取某个内置锁
      如果线程在等待获取一个内部锁,我们将无法中断它。但是,利用Lock类的lockInterruptibly方法,我们可以在等待锁的同时,提供中断能力。

    实战

    考虑以下场景,使用线程池执行任务,任务包含一系列查询操作和一个修改操作,查询操作可能超时。每个任务的超时时间是3秒。如果FutureTask超时返回,而任务还在继续执行,就会造成数据不一致。这时候需要再查询一次任务的结果才知道执行是否成功。而如果超时之后直接查询,有可能任务还在执行中,这时查到的也是不一样的。此时,可以任务外超时处理中,取消任务;同时,任务内在合适的部分,添加是否中断的判断。如:

    //任务外超时处理中,取消任务
    try{
        SaveResult result = task.get(3000, TimeUnit.MILLISECONDS));  //3s超时
    }catch (Exception e){
        if(e instanceof TimeoutException){
            //超时返回,不知道结果,需要取消任务;参数true表示中断正在执行的操作
            task.cancel(true);
        }
    } 
    
    //任务内在合适的部分,添加中断的判断和相关操作
    Future<SaveResult> task = executor.submit(new Callable<SaveResult>() {
        @Override
        public SaveResult call() throws Exception {
            //do something, 1.5s
            //do others, 1.5s
            //任务内,判断当前线程是否被中断,如果已经被中断,则不执行变更操作
            if(!Thread.currentThread.isInterruptrf()){
            	//update sth
            }
            return result ;
        }
    });
    

    看看FutureTask中cancel源码,如果需要中断,则是使用线程中断的方式

    public boolean cancel(boolean mayInterruptIfRunning) {
        if (state != NEW)
            return false;
        if (mayInterruptIfRunning) {
            if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING))
                return false;
            Thread t = runner;
            if (t != null)
                t.interrupt();
            UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // final state
        }
        else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED))
            return false;
        finishCompletion();
        return true;
    }
    

    参考

    Java并发:终止线程和关闭线程池

    java线程中断

  • 相关阅读:
    有趣的F-String
    停止使用非版本控制的可执行代码
    Django ORM中,如何使用Count来关联对象的子集数量
    Django Tastypie: 贴士,技巧和故障排除
    我实在不懂Python的Asyncio
    使用Let's Encrypt为网站加入SSL证书
    [debug]记一次竞态更新bug的解决
    我的web聊天之---序章
    我的音乐盒子(nodejs7 + koa2 + vue + vuex + vue-router)
    装饰器 生成器 进阶
  • 原文地址:https://www.cnblogs.com/shoren/p/java-interrupt.html
Copyright © 2011-2022 走看看