首页 > 编程语言 >已解决:java.util.concurrent.CancellationException 异常的正确解决方法,亲测有效!!!

已解决:java.util.concurrent.CancellationException 异常的正确解决方法,亲测有效!!!

时间:2024-08-09 08:57:08浏览次数:17  
标签:java CancellationException 取消 get util concurrent 任务

在 Java 开发过程中,java.util.concurrent.CancellationException 是一个可能出现的异常,通常发生在使用并发任务时,如 FutureCompletableFuture,当一个任务被取消后,尝试获取其结果时抛出此异常。本文将详细介绍这个异常的发生原因,分析其报错根源,并提供多种有效的解决方案,最后给出预防措施。

问题描述

CancellationException 是一个未检查的异常,通常在以下场景中会出现:

  • 使用 Futureget() 方法获取一个已取消的任务的结果。
  • 使用 CompletableFuture 处理异步操作时,任务被取消。
  • 在线程池中提交任务时,任务在执行过程中被手动或程序逻辑取消。

典型的异常栈如下:

java.util.concurrent.CancellationException
    at java.util.concurrent.FutureTask.report(FutureTask.java:121)
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at com.myproject.Main.main(Main.java:15)

问题分析

CancellationException 主要由以下几个原因引发:

  1. 任务被取消:在并发操作中,一个任务由于超时或用户手动干预被取消。
  2. 错误的任务管理:在获取任务结果前,未检查任务的完成状态。
  3. 线程池管理不当:线程池中的任务被取消后仍尝试获取其结果。

报错原因

  1. 使用 Future 获取结果时任务已被取消:当调用 Future.get() 方法获取结果时,如果任务已取消,就会抛出 CancellationException
  2. 异步任务被取消后使用 CompletableFuture.get():异步任务在执行过程中被取消,之后尝试获取其结果时会抛出此异常。

解决思路

  1. 检查任务状态:在获取任务结果之前,先检查任务的状态,确认任务未被取消。
  2. 异常捕获:在处理任务结果时捕获 CancellationException 并进行适当的处理。
  3. 优化任务取消逻辑:确保只有在必要时取消任务,减少不必要的取消操作。

解决方法

方法一:检查任务状态

在调用 Future.get()CompletableFuture.get() 方法之前,先检查任务是否已被取消。

示例代码
import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(() -> {
            // 模拟长时间运行的任务
            Thread.sleep(5000);
            return "Task completed";
        });

        try {
            // 检查任务是否被取消
            if (!future.isCancelled()) {
                String result = future.get();
                System.out.println(result);
            } else {
                System.out.println("Task was cancelled.");
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } catch (CancellationException e) {
            System.out.println("Caught CancellationException: Task was cancelled.");
        } finally {
            executor.shutdown();
        }
    }
}

方法二:捕获 CancellationException

在获取任务结果时,直接捕获 CancellationException 并进行处理。

示例代码
import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(() -> {
            Thread.sleep(2000);
            return "Task completed";
        });

        future.cancel(true);  // 取消任务

        try {
            String result = future.get();
            System.out.println(result);
        } catch (CancellationException e) {
            System.out.println("Task was cancelled, unable to get the result.");
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}

方法三:使用 CompletableFuture 异步处理

在使用 CompletableFuture 时,可以利用 handle 方法来处理任务的完成状态,包括取消的情况。

示例代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class Main {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Task completed";
        });

        future.cancel(true);  // 取消任务

        future.handle((result, ex) -> {
            if (ex != null) {
                if (ex instanceof CancellationException) {
                    System.out.println("Task was cancelled.");
                } else {
                    ex.printStackTrace();
                }
            } else {
                System.out.println(result);
            }
            return null;
        });

        try {
            future.get(); // 触发 handle
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

方法四:优化任务取消逻辑

在设计并发任务时,尽量减少不必要的任务取消操作,尤其是在任务完成之前。

预防措施

  1. 使用线程池管理任务:使用合适的线程池策略,避免因资源耗尽或管理不当导致的任务取消。
  2. 任务状态监控:在任务执行过程中监控任务的状态,及时发现和处理异常。
  3. 合理设置超时:设置合理的超时参数,避免因任务执行时间过长导致的自动取消。

总结

java.util.concurrent.CancellationException 是 Java 并发编程中常见的异常,通过检查任务状态、捕获异常、优化取消逻辑等方法,可以有效地避免和解决这个问题。希望本文的详细解析和亲测有效的解决方案能帮助开发者更好地处理并发任务中的异常情况。如果有其他问题或疑问,欢迎留言讨论。

通过上述方法和示例代码,开发者可以快速定位并解决 CancellationException 异常,确保 Java 应用程序的稳定运行。

标签:java,CancellationException,取消,get,util,concurrent,任务
From: https://blog.csdn.net/weixin_52489536/article/details/141051872

相关文章

  • 深入浅出Java RestClient与Elasticsearch:一次简单的聚合查询实现
    文章目录一、什么是聚合查询?二、开始编写代码三、代码解析四、总结在当今的大数据时代,Elasticsearch作为一个分布式搜索和分析引擎,被广泛应用于各类数据密集型应用中。而使用Java与Elasticsearch交互进行数据操作时,JavaHighLevelRestClient提供了一种方便且......
  • 哪种编程语言更适合学习数据结构和算法:C++、Java 还是 Python?
    作为一名工程专业的学生,​​我正在尝试决定使用哪种编程语言来学习数据结构和算法(DSA)。我正在考虑C++,它提供高性能和强大的标准模板库,但对于初学者来说可能很复杂。Java具有强大的语法和内置集合,使DSA概念更容易掌握,尽管我不确定它与C++相比的性能。Python以其简单性和......
  • activiti初始化报:java.sql.SQLSyntaxErrorException: Table ‘activiti.act_ge_proper
    在学习activiti过成中,由于使用的MySQL是8版本的,所以报了:org.apache.ibatis.exceptions.PersistenceException: ###Errorqueryingdatabase. Cause:java.sql.SQLSyntaxErrorException:Table'activiti.act_ge_property'doesn'texist###Theerrormayexistinorg/......
  • Java毕业设计 基于Springboot+Vue的公司单位高校党建系统(源码+lw+部署文档+讲解等)
    文末获取资源,收藏关注不迷路文章目录前言主要使用技术研究内容核心代码文章目录前言随着经济的发展,人员交流来往的频繁,党员管理更加需要一套信息系统以提高信息管理的快捷及准确性。智慧党建系统是高校党委组织工作不可缺少的一部分,各功能齐全、简单有用的智慧党建......
  • Java入门学习——Day01初识Java
    一、为什么学习Java1.1Java历史1.1.1背景介绍        Java语言最初由SunMicrosystems的詹姆斯·高斯林(JamesGosling)等人在1991年开始开发,当时SunMicrosystems希望开发一种能够在各种消费电子设备上运行的小型程序语言,最初命名为Oak。        1995年5月......
  • 【JavaEE】锁策略
    目录前言一.悲观锁和乐观锁二.重量级锁和轻量级锁三.挂起等待锁和自旋锁四.公平锁和非公平锁五.可重入锁和不可重入锁六.读写锁synchronized对应的锁策略1.悲观锁和乐观锁2.重量级锁和轻量级锁3.挂起等待锁和自旋锁4.公平锁和非公平锁5.可重入锁和不可重入锁相......
  • Java | Integer强转Double错误
    一、问题复现引发java.lang.ClassCastException:classjava.lang.Integercannotbecasttoclassjava.lang.Double错误的示例代码:publicclassClassCastExceptionExample{publicstaticvoidmain(String[]args){Objectnumber=Integer.valueOf(10);......
  • java中——接口
    接口的作用只能用来调用如果十个人里有三个会游泳,就可以新建一个接口储存swim方法,三人可以通过继承关系调用而抽象是在方法的基础上重写,体现出同一个方法的不同形态如果十个人游泳,但是游泳的姿势不同,如狗刨。。。此时就可以通过抽象继承关系去重写子类的游泳姿势接口的定义和......
  • Java项目:213基于Springboot + vue实现的网上订餐系统(含论文+开题报告+开题PPT)
    作者主页:夜未央5788 简介:Java领域优质创作者、Java项目、学习资料、技术互助文末获取源码项目介绍基于Springboot+vue实现的网上订餐系统前台登录:1.首页:菜品信息推荐、菜品信息展示、查看更多2.菜品信息:菜品分类、菜品名称查询、菜品详情、下单提交3.个人中心:可......
  • 【Java】代码规范
    参考《码出高效:Java开发手册》~是一个读书笔记~目录命名规范包名类名变量常量代码编写规范命名规范所有的命名都需要能看出代码的作用,使用英文单词进行命名包名使用小写字母,相邻的点之间只能有一个单词,使用单数形式例:importjava.util.stream.*;如果类名有复数......