一、简介

在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. 分组,命名分组,url的命名和反向解析

    1.位置分组 匹配到参数,按照位置参数的方式传递给视图函数 视图函数需要定义形参接收变量 1.写在url里面的: # 删除 url(r'^del_class/(\d+)',views.del_clas ...

  2. Java代码审计连载之—SQL注入

    前言近日闲来无事,快两年都没怎么写代码了,打算写几行代码,做代码审计一年了,每天看代码都好几万行,突然发现自己都不会写代码了,真是很DT.想当初入门代码审计的时候真是非常难,网上几乎找不到什么java ...

  3. [vuejs] 深入响应式原理

    深入响应式原理 现在是时候深入一下了!Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是普通的 JavaScript 对象.而当你修改它们时,视图会进行更新.这使得状态管理非常简单直接 ...

  4. datatable插件使用小记

    经验,是前行路上,磕磕碰碰,不断探索,最终留下的结晶:亦是下一次,快速高效,寻求到结果的快捷方式. datatable插件具体可参考: 官网:http://datatables.club/ 参数说明: ...

  5. 条件变量 sync.Cond

    sync.Cond 条件变量是基于互斥锁的,它必须有互斥锁的支撑才能发挥作用. sync.Cond 条件变量用来协调想要访问共享资源的那些线程,当共享资源的状态发生变化的时候,它可以用来通知被互斥锁阻 ...

  6. c++中double类型控制小数位数

    有时,我们需要输出确定小数位数的double,可以先引入如下头文件: #include <iomanip> 然后通过下列方式输出: double zzz = 8.66666; cout & ...

  7. MySQL数据导入到Mongo

    背景:如题干所述,需要将一份数据导入到mongo数据库,减少项目依赖的数据源. 解决方案: 使用mongo自带的mongoimport工具. 首先在test库里创建一个空集合:[import_test ...

  8. 从学CodeSmith谈程序员学习方法

    一直觉得CodeSmith是个好东西,最近正好有点时间来研究下,其实以前也想学习怎么用,在博客园搜一下有很多介绍CodeSmith的文章,我就收藏过一个写得很详细的http://terrylee.cn ...

  9. C/C++求职宝典21个重点笔记(常考笔试面试点)

    这是我之前准备找工作时看<C/C++求职宝典>一书做的笔记,都是一些笔试面试中常考的重点难点问题,但比较基础,适合初学者看. 1. char c = '\72'; 中的\72代表一个字符, ...

  10. Linux-(telnet,wget)

    telnet命令 telnet命令通常用来远程登录.telnet程序是基于TELNET协议的远程登录客户端程序.Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和 ...