shutdownNow的局限性
shutdownNow是强行关闭ExecutorService的,它会尝试取消正在执行的任务,并返回所以已提交但尚未开始的任务,但是我们无法通过常规方法来找出哪些任务已经开始但尚未结束。这意味着我们无法在关闭过程中知道正在执行的任务的状态,除非任务本身会执行某种检查。为此,设计了一个TrackingExecutor类跟踪在关闭之后被取消的任务,getCancelledTasks返回被取消的任务清单。要使这项技术能发挥作用,任务在返回时必须维持线程的中断状态。具体代码如下:
public class TrackingExecutor extends AbstractExecutorService { private final ExecutorService exec = Executors.newCachedThreadPool(); private final Set<Runnable> tasksCancelledAtShutdown = Collections.synchronizedSet(new HashSet<Runnable>()); public List<Runnable> getCancelledTasks(){ if(!exec.isTerminated()){ throw new IllegalStateException("线程尚未中断"); } return new ArrayList<Runnable>(tasksCancelledAtShutdown); } @Override public void execute(final Runnable runnable) { exec.execute(new Runnable() { @Override public void run() { try{ runnable.run(); }finally{ if(isShutdown() && Thread.currentThread().isInterrupted()){ tasksCancelledAtShutdown.add(runnable); } } } }); } /*----------------------将ExecutroService的其他方法委托给exec---------------------------------*/ @Override public void shutdown() { // TODO Auto-generated method stub exec.shutdown(); } @Override public List<Runnable> shutdownNow() { // TODO Auto-generated method stub return exec.shutdownNow(); } @Override public boolean isShutdown() { // TODO Auto-generated method stub return exec.isShutdown(); } @Override public boolean isTerminated() { // TODO Auto-generated method stub return exec.isTerminated(); } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { // TODO Auto-generated method stub return exec.awaitTermination(timeout, unit); } }
使用TrackingExecutorService保存未完成的任务以备后续执行,代码如下:
public abstract class WebCrawler { private static final long TIMEOUT = 1; private static final TimeUnit UNIT = TimeUnit.MILLISECONDS; private volatile TrackingExecutor exec; @GuardedBy("this") private final Set<URL> urlsToCrawl = new HashSet<URL>(); public synchronized void start(){ exec = new TrackingExecutor(Executors.newCachedThreadPool()); for(URL url : urlsToCrawl){ submitCrawlTask(url); } urlsToCrawl.clear(); } public synchronized void stop() throws InterruptedException{ try{ saveUncrawled(exec.shutdownNow()); if(exec.awaitTermination(TIMEOUT, UNIT)){ saveUncrawled(exec.getCancelledTasks()); } }finally{ exec = null; } } private void saveUncrawled(List<Runnable> uncrawled){ for(Runnable task : uncrawled){ urlsToCrawl.add(((CrawlTask) task).getPage()); } } private void submitCrawlTask(URL url) { exec.execute(new CrawlTask(url)); } protected abstract List<URL> processPage(URL url); private class CrawlTask implements Runnable{ private final URL url = null; public CrawlTask(URL url2) { } public void run(){ for(URL link : processPage(url)){ if(Thread.currentThread().isInterrupted()){ return; } submitCrawlTask(link); } } public URL getPage(){return url;} } }
其中在 TrackingExecutor中存在一个不可避免的竞态条件,从而产生“误报”问题:一些被认为已取消的任务实际上已经执行完成。这个问题的原因在于,任务执行最后一条指令以及线程池将任务记录为“结束”的两个时刻之间,线程池可能被关闭。如果任务是幂等的(Idempotent,即将任务执行两次与执行一次会得到相同的结果),那么这不会存在问题,在网页爬虫程序中就是这种情况。否则,在应用程序中必须考虑这种风险,并对“误报”问题做好准备。
相关推荐
JAVA并行计算的一些资料 论文JAVA并行计算的一些资料 论文JAVA并行计算的一些资料 论文JAVA并行计算的一些资料 论文
基于Web的Java并行计算,基于Web的Java并行计算
JAVA并行模式JAVA并行模式JAVA并行模式JAVA并行模式JAVA并行模式JAVA并行模式JAVA并行模式
Java并行程序基础,学习java并行的写作。。。。。。。。。。。。。。。
java的并行编程的样例,jdk1.7中并行框架的样例,多种并行的实现方法
主要介绍了Java8并行流中自定义线程池操作,结合实例形式分析了并行流的相关概念、定义及自定义线程池的相关操作技巧,需要的朋友可以参考下
这个java并行程序设计的经典例子 虽然分多了点 但还是很值得的 完全可以运行 java parallel sort
一共四页, 用图形文字简明扼要地介绍Jdk 6有关系统并行性的一些特性。 能让Java的学习者快速了解Java对并发机制的支持。 是一本难得的好书。
java并行计算 JAVA的MPI---MPJ java并行计算 JAVA的MPI---MPJ java并行计算 JAVA的MPI---MPJ java并行计算 JAVA的MPI---MPJ java并行计算 JAVA的MPI---MPJ
<<java并行编程>>英文版chm格式,英文名称<Java Concurrency in Practice>,一直想买这本书,但总是缺货,找到了电子版,分享给大家。 Java Concurrency in Practice By Brian Goetz, Tim Peierls, Joshua Bloch,...
采用java8的并行计算,完成1到400亿的数列求和,并行计算完成时间3秒左右,采用普通计算完成时间13秒左右,效果明显
实现4线程状态下3分钟计算圆周率小数点后62~63万位
国家863计划项目“网格服务环境结点建设及其支撑技术研究”的子课题 “用户开发环境研究”,旨在开发出以客户端/服务器模式运行的,能在远程编辑、编译、运行、调试并行程序的集成开发环境。并行程序的源代码编辑...
在eclispe下写的爬取200个单词的翻译,并行效果较好
Java并行注释规范JAC的扩展
利用Java的多线程技术实现并行多任务的管理
采用java8的并行计算,完成1到400亿的数列求和,并行计算完成时间3秒左右,采用普通计算完成时间13秒左右,效果明显
基于JAVA平台的多线程与并行的资料
分别使用串行、并行方法计算矩阵乘法,对比两者的执行时间
并行计算实验计算pi的源码,java环境