Java利用异常中断当前任务的技巧分享

 更新时间:2023年08月28日 14:05:26   作者:乐征skyline  
在日常开发中,我们经常遇到调用别人的代码来完成某个任务,但是当代码比较耗时的时候,没法从外部终止该任务,所以本文为大家介绍了如何利用异常中断当前任务,需要的可以参考下

Java小技巧:利用异常中断当前任务

在日常开发中,我们经常遇到调用别人的代码来完成某个任务,但是当代码比较耗时的时候,没法从外部终止该任务。有些程序从开始就考虑到了这个场景,就会提供对应的cancelstop之类的方法用于终止任务,但还是会有很多三方库并没有提供响应接口。比如,下面这个下载示例:

class DownloadTask {
    public void download(Listener listener) {
        try {
            for (int i = 0; i < 100; i++) {//模拟下载过程
                Thread.sleep(1000);
                listener.onProgressUpdated(i + 1);
            }
            listener.onCompleted();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    public interface Listener {
        void onProgressUpdated(int progress);
        void onCompleted();
    }
}
public class Main {
    public static void main(String[] args) throws InterruptedException {
        DownloadTask task = new DownloadTask();
        task.download(new DownloadTask.Listener() {
            @Override
            public void onProgressUpdated(int progress) {
                System.out.println("onProgressUpdated: " + progress);
                if (isInterrupted.get()) {
                    throw new EndException();
                }
            }
            @Override
            public void onCompleted() {
            }
        });
    }
}

这里的DownloadTask开始运行后,就无法直接停止。如果DownloadTask是第三方库的代码时,我们可能不方便改它的代码使其支持中断。本文介绍一种利用异常来终止这样的任务的方法。

(注:本文介绍的方法仅限于单线程或单个子线程的情况,并且需要有在任务运行的线程执行代码的能力,比如回调)

场景1:任务没有另起线程的情况

这个就是上面展示的那个下载示例,我们可以通过回调,直接利用异常中断该任务:

//DownloadTask 同上
public class Main {
    private static volatile boolean isInterrupted;
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {//模拟外部调用,5秒后通过设置isInterrupted来取消任务,也可以把这段代码放到一个新的cancel方法中
            sleep(5000);
            isInterrupted = true;
        }).start();
        try {
            DownloadTask task = new DownloadTask();
            task.download(new DownloadTask.Listener() {
                @Override
                public void onProgressUpdated(int progress) {
                    System.out.println("onProgressUpdated: " + progress);
                    if (isInterrupted) {
                        throw new EndException();
                    }
                }
                @Override
                public void onCompleted() {
                    System.out.println("onCompleted...");
                }
            });
        }catch (EndException e){
            System.out.println("end...");
            //is interrupted, ignore
        }
        Thread.currentThread().join();
    }
    static class EndException extends RuntimeException {
    }
    public static void sleep(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

场景2:任务另起子线程的情况

如果任务另起子线程来执行,那么就没法直接用try-catch来捕获异常,那么就得通过线程的UncaughtExceptionHandler来完成。假如下载的代码是这样的:

public class DownloadTask {
    public void download(Listener listener) {
        new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {//模拟下载过程
                    Thread.sleep(1000);
                    listener.onProgressUpdated(i + 1);
                }
                listener.onCompleted();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();
    }
    public interface Listener {
        void onProgressUpdated(int progress);
        void onCompleted();
    }
}

那么外部调用并终止的代码就是:

public class Main {
    private static volatile boolean isInterrupted;
    public static void main(String[] args) throws InterruptedException {
        Thread.UncaughtExceptionHandler handler = (t, e) -> {
            if(e instanceof EndException){
                System.out.println("end...");
                //is interrupted, ignore
            }
        };
        DownloadTask task = new DownloadTask();
        task.download(new DownloadTask.Listener() {
            @Override
            public void onProgressUpdated(int progress) {
                System.out.println("onProgressUpdated: " + progress);
                if(Thread.currentThread().getUncaughtExceptionHandler() != handler){//注意这里
                    Thread.currentThread().setUncaughtExceptionHandler(handler);
                }
                if (isInterrupted) {
                    throw new EndException();
                }
            }
            @Override
            public void onCompleted() {
                System.out.println("onCompleted...");
            }
        });
        sleep(5000);
        isInterrupted = true;
        Thread.currentThread().join();
    }
    public static class EndException extends RuntimeException {
    }
    public static void sleep(long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

写在最后

大家也能看到,这并不是什么万能的方法,甚至有很大局限,但碰到合适的场景还是可以通过简短的代码来解决问题。

到此这篇关于Java利用异常中断当前任务的技巧分享的文章就介绍到这了,更多相关Java中断任务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot项目如何获取所有的接口

    Springboot项目如何获取所有的接口

    这篇文章主要介绍了Springboot项目如何获取所有的接口,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • mybatis plus开发过程中遇到的问题记录及解决

    mybatis plus开发过程中遇到的问题记录及解决

    这篇文章主要介绍了mybatis plus开发过程中遇到的问题记录及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • SpringBoot Event实现异步消费机制的示例代码

    SpringBoot Event实现异步消费机制的示例代码

    这篇文章主要介绍了SpringBoot Event实现异步消费机制,ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2024-04-04
  • 关于Filter中获取请求体body后再次读取的问题

    关于Filter中获取请求体body后再次读取的问题

    这篇文章主要介绍了关于Filter中获取请求体body后再次读取的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • java解析xml汇总_动力节点Java学院整理

    java解析xml汇总_动力节点Java学院整理

    这篇文章主要介绍了java解析xml汇总_动力节点Java学院整理的相关资料,需要的朋友可以参考下
    2017-07-07
  • Spring Boot快速过滤出一次请求的所有日志

    Spring Boot快速过滤出一次请求的所有日志

    这篇文章主要介绍了Spring Boot快速过滤出一次请求的所有日志,本文讲述了如何使用MDC工具来快速过滤一次请求的所有日志,并通过装饰器模式使得MDC工具在异步线程里也能生效,需要的朋友可以参考下
    2022-11-11
  • Java线程池由浅入深掌握到精通

    Java线程池由浅入深掌握到精通

    什么是线程池?很简单,简单看名字就知道是装有线程的池子,我们可以把要执行的多线程交给线程池来处理,和连接池的概念一样,通过维护一定数量的线程池来达到多个线程的复用
    2021-09-09
  • Mybatis-Plus 全局配置无效的解决方案

    Mybatis-Plus 全局配置无效的解决方案

    这篇文章主要介绍了Mybatis-Plus 全局配置无效的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • 一文教会你如何搭建vue+springboot项目

    一文教会你如何搭建vue+springboot项目

    最近在捣鼓 SpringBoot 与 Vue 整合的项目,所以下面这篇文章主要给大家介绍了关于如何通过一篇文章教会你搭建vue+springboot项目,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • Java super关键字用法实战案例分析

    Java super关键字用法实战案例分析

    这篇文章主要介绍了Java super关键字用法,结合具体案例形式分析了java super关键字调用父类构造方法、属性及方法等相关操作技巧与注意事项,需要的朋友可以参考下
    2019-09-09

最新评论