Java 终止并向执行人提交可催缴款项
这将在一个月内继续,作为我任务的一部分,我尝试使用callables从URL下载文件,并且每当发生异常时,我将尝试重新提交相同的callables,次数最多 问题是,使用当前的方法,我的程序不会在“快乐日”场景中完成所有可调用项后终止,它会永远运行(可能是因为我使用的是非守护线程?它不会在给定的时间后终止吗?) 此外,我相信当前的设计将阻止再次提交失败的可调用项,因为我正在调用Java 终止并向执行人提交可催缴款项,java,multithreading,future,executorservice,callable,Java,Multithreading,Future,Executorservice,Callable,这将在一个月内继续,作为我任务的一部分,我尝试使用callables从URL下载文件,并且每当发生异常时,我将尝试重新提交相同的callables,次数最多 问题是,使用当前的方法,我的程序不会在“快乐日”场景中完成所有可调用项后终止,它会永远运行(可能是因为我使用的是非守护线程?它不会在给定的时间后终止吗?) 此外,我相信当前的设计将阻止再次提交失败的可调用项,因为我正在调用executor.shutdown(),因此每当可调用项失败时,执行器将阻止向执行队列添加新的可调用项 有没有办法克服这
executor.shutdown()
,因此每当可调用项失败时,执行器将阻止向执行队列添加新的可调用项
有没有办法克服这个问题
public class DownloadManager {
int allocatedMemory;
private final int MAX_FAILURES = 5;
private ExecutorService executor;
private CompletionService<Status> completionService;
private HashMap<String, Integer> failuresPerDownload;
private HashMap<Future<Status>, DownloadWorker> URLDownloadFuturevsDownloadWorker;
public DownloadManager() {
allocatedMemory = 0;
executor = Executors.newWorkStealingPool();
completionService = new ExecutorCompletionService<Status>(executor);
URLDownloadFuturevsDownloadWorker = new HashMap<Future<Status>, DownloadWorker>();
failuresPerDownload = new HashMap<String, Integer>();
}
public ArrayList<Status> downloadURLs(String[] urls, int memorySize) throws Exception {
validateURLs(urls);
for (String url : urls) {
failuresPerDownload.put(url, 0);
}
ArrayList<Status> allDownloadsStatus = new ArrayList<Status>();
allocatedMemory = memorySize / urls.length;
for (String url : urls) {
DownloadWorker URLDownloader = new DownloadWorker(url, allocatedMemory);
Future<Status> downloadStatusFuture = completionService.submit(URLDownloader);
URLDownloadFuturevsDownloadWorker.put(downloadStatusFuture, URLDownloader);
}
executor.shutdown();
Future<Status> downloadQueueHead = null;
while (!executor.isTerminated()) {
downloadQueueHead = completionService.take();
try {
Status downloadStatus = downloadQueueHead.get();
if (downloadStatus.downloadSucceeded()) {
allDownloadsStatus.add(downloadStatus);
System.out.println(downloadStatus);
} else {
handleDownloadFailure(allDownloadsStatus, downloadStatus.getUrl());
}
} catch (Exception e) {
String URL = URLDownloadFuturevsDownloadWorker.get(downloadQueueHead).getAssignedURL();
handleDownloadFailure(allDownloadsStatus, URL);
}
}
return allDownloadsStatus;
}
private void handleDownloadFailure(ArrayList<Status> allDownloadsStatus, String URL) {
int failuresPerURL = failuresPerDownload.get(URL);
failuresPerURL++;
if (failuresPerURL < MAX_FAILURES) {
failuresPerDownload.put(URL, failuresPerURL);
// resubmit the same job
DownloadWorker downloadJob = URLDownloadFuturevsDownloadWorker.get(URL);
completionService.submit(downloadJob);
} else {
Status failedDownloadStatus = new Status(URL, false);
allDownloadsStatus.add(failedDownloadStatus);
System.out.println(failedDownloadStatus);
}
}
}
公共类下载管理器{
int分配内存;
私人最终int MAX_故障=5;
私人遗嘱执行人;
私人CompletionService CompletionService;
私有HashMap failuresPerDownload;
私有HashMap URLDownloadFuturevsDownloadWorker;
公共下载管理器(){
allocatedMemory=0;
executor=Executors.newWorkStealingPool();
completionService=新的执行者completionService(执行者);
URLDownloadFuturevsDownloadWorker=新HashMap();
failuresPerDownload=新建HashMap();
}
公共ArrayList downloadURLs(字符串[]URL,int-memorySize)引发异常{
验证URL;
for(字符串url:url){
failuresPerDownload.put(url,0);
}
ArrayList allDownloadsStatus=新ArrayList();
allocatedMemory=memorySize/url.length;
for(字符串url:url){
DownloadWorker URLDownloader=新的DownloadWorker(url,allocatedMemory);
Future downloadStatusFuture=completionService.submit(URLDownloader);
URLDownloadFuturevsDownloadWorker.put(下载状态未来,URLDownloader);
}
executor.shutdown();
未来下载队列头=空;
而(!executor.isTerminated()){
downloadQueueHead=completionService.take();
试一试{
Status downloadStatus=downloadQueueHead.get();
if(downloadStatus.DownloadSuccessed()){
allDownloadsStatus.add(下载状态);
System.out.println(下载状态);
}否则{
handleDownloadFailure(allDownloadsStatus,downloadStatus.getUrl());
}
}捕获(例外e){
字符串URL=URLDownloadFuturevsDownloadWorker.get(downloadQueueHead.getAssignedURL();
handleDownloadFailure(所有下载状态,URL);
}
}
返回所有下载状态;
}
private void handleDownloadFailure(ArrayList allDownloadsStatus,字符串URL){
int failuresperrl=failuresPerDownload.get(URL);
failuresPerURL++;
if(故障率PRURL<最大故障率){
failuresPerDownload.put(URL,failuresperrull);
//重新提交相同的作业
DownloadWorker downloadJob=urldowloadFutureVSDownloadWorker.get(URL);
completionService.submit(下载作业);
}否则{
Status failedDownloadStatus=新状态(URL,false);
allDownloadsStatus.add(failedDownloadStatus);
System.out.println(失败下载状态);
}
}
}
更新:在我将while循环的条件改为计数器而不是之后!executor.isTerminated()
它起作用了。
为什么执行器不终止?您需要在所有工作完成后调用并终止线程
或者,您可以在构建ExecutorService
时提供自己的线程工厂
,并将所有线程标记为守护进程,以便在主线程退出后它们不会使进程保持活动状态。您需要在所有工作完成后调用并终止线程
或者,在构建ExecutorService
时,您可以提供自己的ThreadFactory
,并将所有线程标记为守护进程,以便在主线程退出后它们不会使进程保持活动状态。在javadoc中,我们看到了一些示例
CompletionService<Result> ecs
= new ExecutorCompletionService<Result>(e);
List<Future<Result>> futures
= new ArrayList<Future<Result>>(n);
try {
...
} finally {
for (Future<Result> f : futures)
f.cancel(true);
}
CompletionService ecs
=新的ExecutorCompletionService(e);
上市期货
=新阵列列表(n);
试一试{
...
}最后{
for(未来f:未来)
f、 取消(真);
}
因此,当您需要在javadoc中停止ExecutorCompletionService时,请尝试调用cancel(true),我们看到了一些示例
CompletionService<Result> ecs
= new ExecutorCompletionService<Result>(e);
List<Future<Result>> futures
= new ArrayList<Future<Result>>(n);
try {
...
} finally {
for (Future<Result> f : futures)
f.cancel(true);
}
CompletionService ecs
=新的ExecutorCompletionService(e);
上市期货
=新阵列列表(n);
试一试{
...
}最后{
for(未来f:未来)
f、 取消(真);
}
因此,当您需要停止ExecutorCompletionService时,请尝试在将来调用cancel(true)我在提交可调用项后立即调用shutdown(),但它不会终止我在提交可调用项后立即调用shutdown(),但它不会终止