多线程任务Rollback

2023-10-27

问题:多线程任务,一个任务执行错误,其他任务应该同步取消

1.主线程监视

        主线程监视任务线程,当一个任务线程出现执行错误时,直接调用System.exit(0)结束程序。

        任务线程代码:

package com.example.thread.cancel.listener;

public class TaskThread extends Thread {
    /**
     * 线程名称
     */
    public String name;
    /**
     * 模拟线程执行时长
     */
    public int mockExecMillisecond;
    /**
     * 模拟线程执行结果
     */
    public boolean mockExecStatus;
    /**
     * 线程实际执行结果
     */
    public boolean defaultExecStatus = Boolean.TRUE;

    /**
     * 定义TaskThread构造方法,用于初始化TaskThread对象
     * @param name 线程名称
     * @param mockExecMillisecond 模拟线程执行时长
     * @param mockExecStatus 模拟线程执行结果
     */
    public TaskThread(String name, int mockExecMillisecond, boolean mockExecStatus) {
        this.name = name;
        this.mockExecMillisecond = mockExecMillisecond;
        this.mockExecStatus = mockExecStatus;
    }

    @Override
    public void run() {
        try {
            System.out.printf("%s开始执行\n", this.name);
            Thread.sleep(mockExecMillisecond);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s执行结束,执行时间%sms,执行结果%s\n",
                this.name, this.mockExecMillisecond, this.mockExecStatus);
        defaultExecStatus = mockExecStatus;
    }
}

        主线程代码:

package com.example.thread.cancel.listener;

import java.util.ArrayList;
import java.util.List;

public class TaskListener {
    public static void main(String[] args) {
        List<TaskThread> taskThreads = new ArrayList<>();
        TaskThread taskThreadOne = new TaskThread("taskOne",5000,true);
        TaskThread taskThreadTwo = new TaskThread("taskTwo",3000,true);
        TaskThread taskThreadThree = new TaskThread("taskThree",1000,false);
        taskThreads.add(taskThreadOne);
        taskThreads.add(taskThreadTwo);
        taskThreads.add(taskThreadThree);
        //线程启动
        for (TaskThread taskThread : taskThreads) {
            taskThread.start();
        }
        //模拟监听,通过任务线程的状态判断线程执行结果,并进行相应处理
        for (;;){
            taskThreads.stream().forEach(taskThread ->{
                if (!taskThread.defaultExecStatus){
                    System.out.println("System.exit(0)");
                    System.exit(0);
                }
            });
        }
    }
}

2.Boss&Worker

         创建Boss线程和Worker线程,在Boss线程中定义end方法用于接收Worker线程的通知。创建Worker线程时传入Boss对象,Worker线程执行过程中通过调用Boss对象的end方法进行通知。Boss线程接收到Worker线程通知后,根据Worker线程的执行结果进行相应处理,若Worker线程执行失败则调用System.exit(0)结束程序。

       改进:

        Worker线程中定义cancel方法,用于当前线程的任务取消处理,Boss线程接收到Work线程通知后,根据Worker线程的执行结果进行相应处理,若某一个Worker线程执行失败则调用所有Work对象各自的cancel方法取消任务。

       任务取消:

        线程只能在实际执行过程中进行取消,可以在cancel方法中定义canceling的标志位,在Worker线程的实际执行代码中加入cancel的相关处理(监听)。

        Boss对象代码:

package com.example.thread.cancel.boss;

import java.util.List;

public class Boss {
    private List<Worker> workers = null;

    /**
     * 传入任务线程,线程取消由Boss统一调配发起,不传入则直接调用System.exit(0)退出
     * @param workers 任务线程集合
     */
    public void setWorkers(List<Worker> workers) {
        this.workers = workers;
    }

    /**
     * 多线程任务出现异常,由Boss直接调用系统退出
     * @param exceptionWorker 异常任务线程
     */
    public void end(Worker exceptionWorker) {
        //根据Boss创建时是否传入Worker对象列表workers,来决定是否使用Worker自身进行取消
        if (workers != null && !workers.isEmpty()) {
            workerCancel(exceptionWorker);
        } else if (!exceptionWorker.mockExecStatus) {
            System.out.println("System.exit(0)");
            System.exit(0);
        }
    }

    /**
     * 多线程任务出现异常,由Worker自身进行取消
     * @param exceptionWorker 异常任务线程
     */
    public void workerCancel(Worker exceptionWorker) {
        if (!exceptionWorker.mockExecStatus) {
            for (Worker workerItem : workers) {
                if (workerItem.mockExecStatus) {
                    workerItem.cancel(exceptionWorker);
                }
            }
        }
    }
}

        Worker线程代码:

package com.example.thread.cancel.boss;

public class Worker extends Thread {
    /**
     * 统一调度对象
     */
    public Boss boss;
    /**
     * 线程名称
     */
    public String name;
    /**
     * 模拟线程执行时长
     */
    public int mockExecMillisecond;
    /**
     * 模拟线程执行结果
     */
    public boolean mockExecStatus;
    /**
     * 线程实际运行时长
     */
    private int realExecMillisecond;

    /**
     * 定义Worker构造方法,用于初始化Worker对象
     * @param boss 统一调度对象
     * @param name 线程名称
     * @param mockExecMillisecond 模拟线程执行时长
     * @param mockExecStatus 模拟线程执行结果
     */
    public Worker(Boss boss, String name, int mockExecMillisecond, boolean mockExecStatus) {
        this.boss = boss;
        this.name = name;
        this.mockExecMillisecond = mockExecMillisecond;
        this.mockExecStatus = mockExecStatus;
    }

    @Override
    public void run() {
        try {
            System.out.printf("%s开始执行\n", this.name);
            //模拟线程执行过程
            int mockExecMillisecondUnit = 1000;
            for (int i = 0; i < mockExecMillisecond / mockExecMillisecondUnit; i++) {
                Thread.sleep(mockExecMillisecondUnit);
                realExecMillisecond += mockExecMillisecondUnit;
                //通过判断mockExecStatus标志位,模拟Worker取消操作
                if (!mockExecStatus) {
                    System.out.printf("%s执行异常,执行时间%sms,执行结果%s\n",
                            this.name, this.realExecMillisecond, false);
                    boss.end(this);
                    return;
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //线程执行完毕
        System.out.printf("%s执行结束,执行时间%sms,执行结果%s\n",
                this.name, this.mockExecMillisecond, this.mockExecStatus);
        if (!mockExecStatus) {
            boss.end(this);
        }
    }

    /**
     * Worker线程定义取消方法,供Boss调用
     * @param exceptionWorker 异常任务线程
     */
    public void cancel(Worker exceptionWorker) {
        //修改标志位,在Worker业务线程中处理取消操作
        mockExecStatus = false;
        System.out.printf("%s执行异常,%s取消中,已执行时间%sms\n",
                exceptionWorker.name, this.name, this.realExecMillisecond);
    }
}

        主线程代码:

package com.example.thread.cancel.boss;

import java.util.ArrayList;
import java.util.List;

public class WorkerNotifyBoss {
    public static void main(String[] args) {
        Boss boss = new Boss();
        List<Worker> workers = new ArrayList<>();
        Worker workerOne = new Worker(boss,"taskOne",5000,true);
        Worker workerTwo = new Worker(boss,"taskTwo",3000,true);
        Worker workerThree = new Worker(boss,"taskThree",1000,false);
        workers.add(workerOne);
        workers.add(workerTwo);
        workers.add(workerThree);
        boss.setWorkers(workers);
        //线程启动
        for (Worker worker: workers) {
            worker.start();
        }
    }
}

3.使用CompletableFuture

        使用CompletableFuture线程池的supplyAsync方法异步处理多个任务,并使用thenAccept方法异步获取任务返回结果,并使用Lambda表达式定义异步任务返回后需要调用的callback方法,在callback方法中实现任务的取消和回滚操作。

        任务执行过程需要根据CompletableFuture线程池异步返回的任务执行结果取消所有任务并执行rollback操作,rollback操作需要根据实际的业务场景实现,用于撤销之前已执行的操作。

        任务对象代码:

package com.example.thread.cancel;

public class Task {
    /**
     * 线程名称
     */
    public String name;
    /**
     * 模拟线程执行时长
     */
    public int mockExecMillisecond;
    /**
     * 模拟线程执行结果
     */
    public boolean mockExecStatus;
    /**
     * 线程实际运行时长
     */
    private int realExecMillisecond;

    /**
     * 定义Task构造方法,用于初始化Task对象
     * @param name 线程名称
     * @param mockExecMillisecond 模拟线程执行时长
     * @param mockExecStatus 模拟线程执行结果
     */
    public Task(String name, int mockExecMillisecond, boolean mockExecStatus) {
        this.name = name;
        this.mockExecMillisecond = mockExecMillisecond;
        this.mockExecStatus = mockExecStatus;
    }

    /**
     * 模拟任务执行方法,返回执行结果
     * @return boolean
     */
    public boolean runTask() {
        try {
            System.out.printf("%s开始执行\n", this.name);
            int mockExecMillisecondUnit = 1000;
            for (int i = 0; i < mockExecMillisecond / mockExecMillisecondUnit; i++) {
                Thread.sleep(mockExecMillisecondUnit);
                realExecMillisecond += mockExecMillisecondUnit;
                //通过判断mockExecStatus标志位,模拟Worker取消操作
                if (!mockExecStatus) {
                    System.out.printf("%s执行异常,执行时间%sms,执行结果%s\n",
                            this.name, this.realExecMillisecond, false);
                    return false;
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s执行结束,执行时间%sms,执行结果%s\n",
                this.name, this.mockExecMillisecond, true);
        return mockExecStatus;
    }

    /**
     * 模拟任务回滚过程
     * @param task 任务对象
     */
    public void rollback(Task task) {
        //修改标志位,在Task任务中处理取消操作
        mockExecStatus = false;
        System.out.printf("%s执行异常,%s取消中,已执行时间%sms\n",
                task.name, this.name, this.realExecMillisecond);
    }
}

        主线程代码:

package com.example.thread.cancel;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

public class TaskCompletableFuture {
    public static List<Task> tasks = new ArrayList<>();

    public static void main(String[] args) {
        Task taskOne = new Task("taskOne", 5000, true);
        Task taskTwo = new Task("taskTwo", 3000, true);
        Task taskThree = new Task("taskThree", 1000, false);
        tasks.add(taskOne);
        tasks.add(taskTwo);
        tasks.add(taskThree);
        //线程交由CompletableFuture异步执行
        for (Task task : tasks) {
            CompletableFuture.supplyAsync(() -> task.runTask())
                    .thenAccept((result) -> callback(result, task));
        }
        //程序暂停,等待CompletableFuture异步执行
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据CompletableFuture任务返回结果,取消所有任务
     * @param result 任务执行返回结果
     * @param task 任务对象
     */
    public static void callback(boolean result, Task task) {
        if (!result) {
            for (Task taskItem : tasks) {
                if (taskItem.mockExecStatus){
                    taskItem.rollback(task);
                }
            }
        }
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多线程任务Rollback 的相关文章

  • 在 Java 中克隆对象 [3 个问题]

    这样做会调用Asub的clone方法吗 或者Asub深度克隆是否正确 如果没有的话 有没有办法通过这种方法对Asub进行深度克隆呢 abstract class Top extends TopMost protected Object cl
  • 如何通过 javaconfig 使用 SchedulerFactoryBean.schedulerContextAsMap

    我使用 Spring 4 0 并将项目从 xml 移至 java config 除了访问 Service scheduleService 带注释的类来自QuartzJobBean executeInternal 我必须让它工作的 xml 位
  • 在内存中使用 byte[] 创建 zip 文件。 Zip 文件总是损坏

    我创建的 zip 文件有问题 我正在使用 Java 7 我尝试从字节数组创建一个 zip 文件 其中包含两个或多个 Excel 文件 应用程序始终完成 没有任何异常 所以 我以为一切都好 当我尝试打开 zip 文件后 Windows 7 出
  • 使用 LinkedList 实现下一个和上一个按钮

    这可能是一个愚蠢的问题 但我很难思考清楚 我编写了一个使用 LinkedList 来移动加载的 MIDI 乐器的方法 我想制作一个下一个和一个上一个按钮 以便每次单击该按钮时都会遍历 LinkedList 如果我硬编码itr next or
  • .properties 中的通配符

    是否存在任何方法 我可以将通配符添加到属性文件中 并且具有所有含义 例如a b c d lalalala 或为所有以结尾的内容设置一个正则表达式a b c anything 普通的 Java 属性文件无法处理这个问题 不 请记住 它实际上是
  • 动态选择端口号?

    在 Java 中 我需要获取端口号以在同一程序的多个实例之间进行通信 现在 我可以简单地选择一些固定的数字并使用它 但我想知道是否有一种方法可以动态选择端口号 这样我就不必打扰我的用户设置端口号 这是我的一个想法 其工作原理如下 有一个固定
  • Spring AspectJ 在双代理接口时失败:无法生成类的 CGLIB 子类

    我正在使用Spring的
  • 过滤两次 Lambda Java

    我有一个清单如下 1 2 3 4 5 6 7 和 预期结果必须是 1 2 3 4 5 6 7 我知道怎么做才能到7点 我的结果 1 2 3 4 5 6 我也想知道如何输入 7 我添加了i gt i objList size 1到我的过滤器
  • 如何获取之前的URL?

    我需要调用我的网络应用程序的 URL 例如 如果有一个从 stackoverflow com 到我的网站 foo com 的链接 我需要 Web 应用程序 托管 bean 中的 stackoverflow 链接 感谢所有帮助 谢谢 并不总是
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 从最终实体获取根证书和中间证书

    作为密码学的菜鸟 我每天都会偶然发现一些简单的事情 今天只是那些日子之一 我想用 bouncy castle 库验证 java 中的 smime 消息 我想我几乎已经弄清楚了 但此时的问题是 PKIXparameters 对象的构建 假设我
  • 将流转换为 IntStream

    我有一种感觉 我在这里错过了一些东西 我发现自己做了以下事情 private static int getHighestValue Map
  • 将 MOXy 设置为 JAXB 提供程序,而在同一包中没有属性文件

    我正在尝试使用 MOXy 作为我的 JAXB 提供程序 以便将内容编组 解组到 XML JSON 中 我创建了 jaxb properties 文件 内容如下 javax xml bind context factory org eclip
  • jdbc mysql loginTimeout 不起作用

    有人可以解释一下为什么下面的程序在 3 秒后超时 因为我将其设置为在 3 秒后超时 12秒 我特意关闭了mysql服务器来测试mysql服务器无法访问的这种场景 import java sql Connection import java
  • Java ResultSet 如何检查是否有结果

    结果集 http java sun com j2se 1 4 2 docs api java sql ResultSet html没有 hasNext 方法 我想检查 resultSet 是否有任何值 这是正确的方法吗 if resultS
  • tomcat 中受密码保护的应用程序

    我正在使用 JSP Servlet 开发一个Web应用程序 并且我使用了Tomcat 7 0 33 as a web container 所以我的要求是tomcat中的每个应用程序都会password像受保护的manager applica
  • logcat 中 mSecurityInputMethodService 为 null

    我写了一点android应显示智能手机当前位置 最后已知位置 的应用程序 尽管我复制了示例代码 并尝试了其他几种解决方案 但似乎每次都有相同的错误 我的应用程序由一个按钮组成 按下按钮应该log经度和纬度 但仅对数 mSecurityInp
  • 为什么 Java 8 不允许非公共默认方法?

    让我们举个例子 public interface Testerface default public String example return Hello public class Tester implements Testerface
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • Opencv Java 灰度

    我编写了以下程序 尝试从彩色转换为灰度 Mat newImage Imgcodecs imread q1 jpg Mat image new Mat new Size newImage cols newImage rows CvType C

随机推荐

  • [苹果开发者账号]04 申请苹果开发者账号 美国报税表

    申请苹果开发者账号时 当银行信息完成后 要填写美国报税表 填写时注意的地方 1 首先 选择报税表 使用默认的美国 2 填写美国报税表 中国的公司和中国人 全选否 3 填写详细的报税表 记录下红色箭头部分 选Corporation 公司 写报
  • python资料大全

    前言 Python是一种高级编程语言 已经成为了当今最受欢迎的编程语言之一 它被广泛用于Web开发 数据科学 人工智能 机器学习等领域 Python具有易学易用的特点 同时也具有强大的功能和灵活性 本篇博客将介绍Python的学习过程以及它
  • 多线程学习----join()的用法

    join的用法一 join 方法可以使得一个线程在另一个线程结束后再执行 如果join 方法在一个线程实例上调用 当前运行着的线程将阻塞直到这个线程实例完成了执行 首先来看个例子 author QingHe Creation on 2005
  • 修复office 2007或2010安装程序找不到Proplas.ww/Proplsww.cab

    此情况一般是我们删除了缓存MSOCache出现的 在安装office2007或10的盘下 默认是C盘 有一个隐藏文件MSOCache 在里面的All Users文件下创建 90120000 0011 0000 0000 0000000FF1
  • 二叉树的遍历C#实现,递归以及非递归

    前序遍历 输出规则 根节点 左子树 右子树 二叉树的前序遍历规则是从根节点开始 依层 逐层取 左子节点 若此节点没有 左子节点 说明此节点是叶子节点 往上 回溯 取 最小父节点的右节点 再重复 此步骤 取左子节点 直到 没有左子节点 也没有
  • 结构化方法与面向对象方法的比较

    结构化方法与面向对象方法的比较 一 结构化方法 结构化方法 Structured Methodology 采用了系统科学的思想方法 从层次的角度 自顶向下地分析和设计系统 结构化方法包括结构化分析 Structured Analysis 简
  • 20多岁年轻人应该有多少存款?

    20多岁年轻人应该有多少存款 本人22应届专升本软件工程毕业 在专科阶段做了很多兼职 保安 销售 服务员 兼职只能够个日常开销 还记得疫情那年 我专科还没毕业 被困在家里 后面4月份解封 我就早早的跟朋友去外面找工作 找了一份快递的工作 本
  • 数据结构:Trie字符串统计

    维护一个字符串集合 支持两种操作 I x 向集合中插入一个字符串 x Q x 询问一个字符串在集合中出现了多少次 共有 N 个操作 所有输入的字符串总长度不超过 1e5 字符串仅包含小写英文字母 Trie树 高效存储和查找字符串 按树结构存
  • 机器学习实践(2.1)LightGBM分类任务

    前言 LightGBM也属于Boosting集成学习模型 还有前面文章的XGBoost LightGBM和XGBoost同为机器学习的集大成者 相比越来越流行的深度神经网络 LightGBM和XGBoost能更好的处理表格数据 并具有更强的
  • 【Transformer】2、ViT:An image is worth 16x16: transformers for image recognition at scale

    文章目录 一 背景和动机 二 方法 三 效果 四 Vision Transformer 学习到图像的哪些特征了 五 代码 代码链接 https github com lucidrains vit pytorch 论文连接 https ope
  • Android Listview 以及list view适配器

    Listview 相关监听事件以及滑动按钮 适配器 是来连接数据源和图形化界面的桥梁 数组适配器arrayadapter 集合和数组 格式简单 简单适配器simpleadapter格式复杂 使用过程 星舰 添加数据元到适配器 试图展示 si
  • JAVA中scanner方法详解

    Scanner 是 Java 中的一个比较重要的类 它的作用是用来从控制台读取输入的 它可以接收字符串 整数等类型的输入 使用方法如下 1 使用 Scanner 对象 创建 Scanner 对象并传入要接收输入的字符串 Scanner in
  • 图像边缘特征

    图像边缘是图像的重要特征 是图像中特性 如像素灰度 纹理等 分布的不连续处 图像周围特性有阶跃变化或屋脊状变化的那些像素集合 图像的边缘部分集中了图像的大部分信息 一幅图像的边缘结构与特点往往是决定图像特质的重要部分 图像边缘的另一个定义是
  • scp命令传输出现ssh: Could not resolve hostname错误

    ssh Could not resolve hostname xxxxx Temporary failure in name resolution 原因是docker导出的镜像需要离线导入 在命名的时候根据docker镜像命名带上了 导致
  • 海思3559A上编译libjpeg-turbo源码操作步骤

    1 从https github com libjpeg turbo libjpeg turbo releases tag 2 0 2 下载libjpeg turbo 2 0 2版本 2 脚本build sh内容如下 cmake DCMAKE
  • Redis五种数据结构及常用操作指令、Redis在JAVA中如何封装使用

    由于在博主的博客专栏 杂货铺实战 中的杂货铺项目中用到了Redis 那么本篇博文就针对Redis的五种数据结构以及如何在JAVA中封装使用做一个简单的介绍 文章目录 数据结构 string字符串 string字符串简介 string字符串在
  • nginx代理常见问题

    1 http200 但是返回We re sorry but XXXX doesn t work properly without JavaScript enabled Please enable it to continue 项目1 可能原
  • React.js 之筛选篇

    span style font size 14px 这个框架有听过好几次了 但自己没实现过 今天终于自己学了下 模仿写了这个过滤 妙味视频里面的 目前遇到的情况是用babel会丢失代码提示 但在浏览器中可视 划分组件 组件链接 span
  • 交叉熵损失函数优缺点_如何简单通俗的理解交叉熵损失函数?

    前面小编给大家简单介绍过损失函数 今天给大家继续分享交叉熵损失函数 直接来看干货吧 一 交叉熵损失函数概念 交叉熵损失函数CrossEntropy Loss 是分类问题中经常使用的一种损失函数 公式为 接下来了解一下交叉熵 交叉熵Cross
  • 多线程任务Rollback

    问题 多线程任务 一个任务执行错误 其他任务应该同步取消 1 主线程监视 主线程监视任务线程 当一个任务线程出现执行错误时 直接调用System exit 0 结束程序 任务线程代码 package com example thread c