一、简介

在Java并发编程中,“毒丸”指的是将一个对象放在队列当中,当得到这个对象的时候立即停止执行

下面是一个使用“毒丸”来取消任务的一个示例

如图所示,我们假设一个任务从开始到结束需要经历4个步骤,正常情况下4个步骤将会顺序执行。

而在任务的执行过程中,我们由于一些原因需要取消这个任务,那这个时候我们设置一个“毒丸”,每个步骤在执行开始的时候会进行校验,如果遇到“毒丸”那么将终止执行。

考虑到添加“毒丸”的时候,上一个任务可能还在执行中,所以添加毒丸以后,需要对上一个步骤进行清理,例如:上一个步骤是在查询数据库,那么可能你需要把数据库的查询中断掉

二、示例代码

PoisonDemo

public class PoisonDemo {
public static void main(String[] args) {
// 实例化一个任务
final Task task = new Task();
// 另起一个线程,在2秒以后取消任务
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
task.cancel();
}
}).start();
// 主线程执行任务
task.execute();
}
}

Task

public class Task {
private String[] stepNames = { "step1", "step2", "step3", "step4" };
private int currentIndex = 0;
private TaskCancelManager manager = new TaskCancelManager(); public void execute() {
System.out.println("任务开始执行 steps=" + Arrays.asList(stepNames));
Step currStep = null;
while (true) {
if (currentIndex + 1 > stepNames.length) {
break;
}
// 执行任务
String stepName = stepNames[currentIndex];
boolean success = manager.addStep(stepName);
if (!success) {
System.out.println(stepName + " 不继续执行");
// 清理上一个步骤的数据
if (currStep != null) {
currStep.purge();
}
break;
}
// 获取当前步骤,并执行
currStep = new Step(stepName);
currStep.execute();
currentIndex++;
}
System.out.println("任务执行结束 steps=" + manager.getStepNames());
} public void cancel() {
manager.addPoison();
}
}

Step

public class Step {
private String stepName; public Step(String stepName) {
this.stepName = stepName;
} public void execute() {
System.out.println(stepName + " 开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(stepName + " 结束执行");
} public void purge() {
System.out.println("任务中断,清理" + stepName + "步骤");
}
}

TaskCancelManager:这里采用同步锁来控制添加“毒丸”和“步骤”是互斥的

public class TaskCancelManager {
private static final String POISON = "poison"; private List<String> stepNames = new ArrayList<String>(); public synchronized boolean addStep(String stepName) {
// 如果上一个是毒丸
if (stepNames.size() > 0 && stepNames.get(stepNames.size() - 1).equals(POISON)) {
return false;
}
stepNames.add(stepName);
return true;
} public synchronized void addPoison() {
stepNames.add(POISON);
} public List<String> getStepNames() {
return stepNames;
}
}

我们运行程序,最后输出内容为:

任务开始执行 steps=[step1, step2, step3, step4]
step1 开始执行
step1 结束执行
step2 开始执行
step2 结束执行
step3 不继续执行
任务中断,清理step2步骤
任务执行结束 steps=[step1, step2, poison]

Java“毒丸”使用示例,实现取消任务的更多相关文章

  1. [译]Java Thread Sleep示例

    Java Thread Sleep示例 java.lang.Thread sleep(long millis)方法被用来暂停当前线程的执行,暂停时间由方法参数指定,单位为毫秒.注意参数不能为负数,否则 ...

  2. [译]Java Thread join示例与详解

    Java Thread join示例与详解 Java Thread join方法用来暂停当前线程直到join操作上的线程结束.java中有三个重载的join方法: public final void ...

  3. 多线程Java Socket编程示例

    package org.merit.test.socket; import java.io.BufferedReader; import java.io.IOException; import jav ...

  4. Java开发Hbase示例

    Java开发Hbase示例 使用Hbase操作数据 package com.sunteng.clickidc.test; import java.io.IOException; import java ...

  5. Java代理模式示例程序

    Java代理模式示例程序 当然不是我想出来的,是我看的一个网上教程里的. 模拟的是一个对电脑公司的代理 真实类的接口: public interface SaleComputer { public S ...

  6. Java广度优先爬虫示例(抓取复旦新闻信息)

    一.使用的技术 这个爬虫是近半个月前学习爬虫技术的一个小例子,比较简单,怕时间久了会忘,这里简单总结一下.主要用到的外部Jar包有HttpClient4.3.4,HtmlParser2.1,使用的开发 ...

  7. java 动态代理示例,带主要注释

    Java proxy是基于反射,仅仅支持基于接口的动态代理. java 动态代理是一切架构的基础,必须了解. 废话少说,先上代码获得感性认识. 示例代码有主要注释. 接口: public interf ...

  8. 从一个简单的Java单例示例谈谈并发

    一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这么写 public class UnsafeLazyInitiallization { private static Un ...

  9. 多线程Java Socket编程示例(转)

    这篇做为学习孙卫琴<<Java网络编程精解>>的学习笔记吧.其中采用Java 5的ExecutorService来进行线程池的方式实现多线程,模拟客户端多用户向同一服务器端发送 ...

随机推荐

  1. DevExpress中获取GridControl排序之后的List

    public System.Collections.IList GetGridViewFilteredAndSortedData(DevExpress.XtraGrid.Views.Grid.Grid ...

  2. MVC 5 Strongly Typed Views(强类型视图)

    学习MVC这样久以来,发觉网站上很多MVC的视频或是文章,均是使用Strongly Type views来实现控制器与视图的交互.Insus.NET以前发布的博文中,也大量使用这种方式: <Da ...

  3. [leetcode.com]算法题目 - Gray Code

    The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...

  4. 【Vue】浅谈Vue不同场景下组件间的数据交流

    浅谈Vue不同场景下组件间的数据“交流”   Vue的官方文档可以说是很详细了.在我看来,它和react等其他框架文档一样,讲述的方式的更多的是“方法论”,而不是“场景论”,这也就导致了:我们在阅读完 ...

  5. Django 实现第三方账号登录网站

    这里我们使用 django-allauth 模块来实现第三方账号验证登录,官方文档如下:https://django-allauth.readthedocs.io/en/latest/ . 安装 dj ...

  6. underscore.js源码研究(1)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  7. Shell - 简明Shell入门02 - 变量(Variable)

    示例脚本及注释 #!/bin/bash v1=test-variable_123 # 全局变量 v2=12345 v3='This is a test!' # 赋值语句使用单引号或双引号可以包含空格 ...

  8. 课程一(Neural Networks and Deep Learning),第四周(Deep Neural Networks)—— 0.学习目标

    Understand the key computations underlying deep learning, use them to build and train deep neural ne ...

  9. matlab中元胞数组的创建与内容读取

    一.创建元胞数组 1.用cell命令创建规格为2*2的空元胞 >> a=cell(2,2) a = [] [] [] [] 2.用大括号"{}"创建元胞数组并赋值 &g ...

  10. 三:理解Page类的运行机制(例:在render方法中生成静态文件)

    我这里只写几个常用的事件1.OnPreInit:此事件后将加载个性化信息和主题2.OnInit:初始化页面中服务器控件的默认值但控件的状态没有加载,没有创建控件树3.OnPreLoad:控件完成状态和 ...