Java利用异常中断当前任务的技巧分享
Java小技巧:利用异常中断当前任务
在日常开发中,我们经常遇到调用别人的代码来完成某个任务,但是当代码比较耗时的时候,没法从外部终止该任务。有些程序从开始就考虑到了这个场景,就会提供对应的cancel
或stop
之类的方法用于终止任务,但还是会有很多三方库并没有提供响应接口。比如,下面这个下载示例:
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中断任务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
最新评论