如何立即停止使用ExecutorService启动的任务? [英] How to stop immediately a task which is started using an ExecutorService?

查看:339
本文介绍了如何立即停止使用ExecutorService启动的任务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试了许多不同的方法来立即停止使用ExecutorService启动的任务,没有运气。

 未来< ; Void> future = executorService.submit(new Callable< Void>(
public Void call(){
... do many other things here ..
if(Thread.currentThread.isInterrupted())
return null;
}
...在这里做很多其他事情。
if(Thread.currentThread.isInterrupted()){
return null;
}
}
));

if(flag){//可能为true并直接取消任务
future.cancel(true);
}

有时我需要在启动后立即取消任务,好奇,为什么我想这样做,你可以想象一个用户意外点击下载按钮开始一个下载任务,他立即想取消操作,因为它只是一个意外的点击。



问题是在调用 future.cancel(true)后,任务不会停止, Thread.currentThread.isInterrupted strong>仍然返回 false ,我无法知道任务是否从call()方法内停止。



在调用future.cancel(true)并在call()方法中不断检查该标志后,设置像 cancelled = true 的标志,我认为这是一个黑客,代码可能非常丑陋,可以在同一时刻启动许多任务。



有更优雅的方式达到我想要的效果吗?



EDIT:



这真的让我疯狂。我现在花了差不多一天这个问题。



我执行以下操作来启动5个任务,每个任务将启动5个线程来下载一个文件。然后我立即停止所有5个任务 。对于下面的所有方法调用,我启动一个线程(ExecutorService.submit(task))使它异步,你可以从方法的后缀告诉。

  int t1 = startTaskAysnc(task1); 
int t2 = startTaskAysnc(task2);
int t3 = startTaskAysnc(task3);
int t4 = startTaskAysnc(task4);
int t5 = startTaskAysnc(task5);

int stopTaskAysnc(t1);
int stopTaskAysnc(t2);
int stopTaskAysnc(t3);
int stopTaskAysnc(t4);
int stopTaskAysnc(t5);在 startTaskAysnc()中的

,我只需启动一个套接字连接到远程服务器获取文件的大小(这当然是需要一些时间),成功获得fileSize后,我将开始5线程下载文件的不同部分。 (下面的代码被简化,使它更容易遵循):

  public void startTaskAsync(DownloadTask task){
Future< Void> future = executorService.submit(new Callable< Void>(
public Void call(){
//这是同步调用
int fileSize = getFileSize();
系统。 out.println(Thread.currentThread.isInterrupted());
....
Future< Void> futures = new Future< Void> [5];
for(int i = 0 ; i< futures.length; ++ i){
futures [i] = executorService.submit(new Callable< Void>(){...});
}
b $ b for(int i = 0; i futures [i] .get(); //等待它完成
}
}
));
synchronized(mTaskMap){
mTaskMap.put(task.getId(),future);
}
}

public void stopTaskAysnc(int taskId){
executorService.execute(new Runnable(){
Future< Void> future = mTaskMap .get(taskId);
future.cancel(true);
});
}

我注意到一个奇怪的行为,在我为所有5个任务调用stopTaskAsync ,总有至少一个任务停止(即Thread.currentThread.isInterrupted()返回true),其他4个任务保持运行。



我已经通过设置UncaughtExceptionHandler来尝试你的建议,但是没有发现。



编辑: >

此链接中的问题已解决:无法停止使用ExecutorService启动的任务

解决方案

a href =http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html#cancel%28boolean%29 =nofollow> javadoc Future.cancel(boolean)说:


如果任务已经开始,那么mayInterruptIfRunning
参数确定执行此任务的线程是否应该
中断,试图停止该任务。


,因此确定执行任务的线程中断。可能发生的是


...在这里做很多其他事情。


意外清除线程中断状态执行所需的
处理。如果你在 Thread.interrupt()中插入一个断点,你可能会抓到犯罪分子。



可以想到的是任务在捕获中断之前终止,要么是因为它已完成或抛出一些未捕获的异常。调用 Future.get()来确定。无论如何,asdasd提到,一个好的做法是设置 UncaughtExceptionHandler


I have tried many different ways to immediately stop a task which is started using an ExecutorService, with no luck.

Future<Void> future = executorService.submit(new Callable<Void>(
    public Void call () {
        ... do many other things here..
        if(Thread.currentThread.isInterrupted()) {
            return null;
        }
        ... do many other things here..
        if(Thread.currentThread.isInterrupted()) {
            return null;
        }
    }
));

if(flag) { // may be true and directly cancel the task
    future.cancel(true);
}

Sometimes I need to cancel the task immediately after it is started, you may be curious why I want to do this, well you may imagine a senario that a user accidentally hits the "Download" button to start a "Download Task" and he immediately wants to cancel the action because it was just an accidental click.

The problem is that after calling future.cancel(true), the task is not stopped and Thread.currentThread.isInterrupted() still returns false and I have no way to know the task was stopped from inside the call() method.

I am thinking of setting a flag like cancelled=true after calling future.cancel(true) and checking that flag constantly in the call() method, I think this is a hack and the code could be very ugly because the user can start many tasks at the same moment.

Is there a more elegant way of achieving what I want?

EDIT:

This really drives me mad. I have spent almost a day on this problem now. I will try to explain a little bit more for the problem I am facing.

I do the following to start 5 tasks, each task will start 5 threads to download a file. and then I stop all 5 tasks immediately. For all of the method calls below, i start a thread(ExecutorService.submit(task)) to make it asynchronous as you can tell from the suffixes of the methods.

int t1 = startTaskAysnc(task1);
int t2 = startTaskAysnc(task2);
int t3 = startTaskAysnc(task3);
int t4 = startTaskAysnc(task4);
int t5 = startTaskAysnc(task5);

int stopTaskAysnc(t1);
int stopTaskAysnc(t2);
int stopTaskAysnc(t3);
int stopTaskAysnc(t4);
int stopTaskAysnc(t5);

in startTaskAysnc(), I simply initiate a socket connection to remote server to get the size of the file(and this certainly is gonna take some time), after successfully getting the fileSize, I will start 5 threads to download different parts of the file. like the following(the code is simplified to make it more easy to follow):

public void startTaskAsync(DownloadTask task) { 
    Future<Void> future = executorService.submit(new Callable<Void>(
        public Void call () {
            // this is a synchronous call
            int fileSize = getFileSize();
            System.out.println(Thread.currentThread.isInterrupted());
            ....
            Future<Void> futures = new Future<Void>[5];
            for (int i = 0; i < futures.length; ++i) {
                futures[i] = executorService.submit(new Callable<Void>(){...});
            }

            for (int i = 0; i < futures.length; ++i) {
                futures[i].get(); // wait for it to complete
            }            
        }
    ));
    synchronized (mTaskMap) {
        mTaskMap.put(task.getId(), future);
    }
}

public void stopTaskAysnc(int taskId) {
    executorService.execute(new Runnable(){
        Future<Void> future = mTaskMap.get(taskId);
        future.cancel(true);
    });
}

I noticed a weird behavior that after I called stopTaskAsync() for all 5 tasks, there would always be at least one task that got stopped(i.e. Thread.currentThread.isInterrupted() return true), and the other 4 tasks kept running.

And I have tried your suggestions by setting an UncaughtExceptionHandler, but nothing comes out from that.

EDIT:

The problem was solved in this link: Can't stop a task which is started using ExecutorService

解决方案

Well, the javadoc of Future.cancel(boolean) says that:

If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.

so it's quite certain that the thread that executes the task is interrupted. What could have happened is that one of the

... do many other things here..

is accidentally clearing the Thread's interrupted status without performing the desired handling. If you'll put a breakpoint in Thread.interrupt() you might catch the criminal.

Another option I can think of is that the task terminates before capturing the interrupt, either because it's completed or thrown some uncaught exception. Call Future.get() to determine that. Anyway, as asdasd mentioned, it is a good practice to set an UncaughtExceptionHandler.

这篇关于如何立即停止使用ExecutorService启动的任务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆