Как отменить ExecutorService в Java - PullRequest
       20

Как отменить ExecutorService в Java

3 голосов
/ 06 ноября 2011

Я написал приложение, которое запускает некоторые потоки, используя ExecutorService, и ждет, пока они не завершатся следующим образом:

ExecutorService exService;
exService = Executors.newCachedThreadPool();
exService.execute(T1);
exService.execute(T2);
exService.shutdown();
boolean finshed = exService.awaitTermination(5, TimeUnit.MINUTES);

иногда мне нужно отменить выполнение этих потоков (всего ExecutorService).
Я пытался exService.shutdownNow(), но выдает java.lang.InterruptedException и не отменяет потоки.
Как отменить выполнение этих потоков?


РЕДАКТИРОВАТЬ: код класса T1 добавлен как Nandaзапрос

public class TC implements Runnable{
    private ExtractedDataBuffer Buffer;
    private Scraper scraper;
    private String AppPath;
    private boolean Succeed=false;
    private Map<String,Object> Result=null;
    private JLabel StatElement;

    public TC(ExtractedDataBuffer Buffer,String AppPath,String XMLfile,JLabel Stat) throws FileNotFoundException {
        this.Buffer = Buffer;
        this.AppPath=AppPath;
        this.StatElement=Stat;

        ScraperConfiguration config;
        config = new ScraperConfiguration(AppPath + Main.XMLFilesPath +XMLfile);
        scraper = new Scraper(config, AppPath);
    }

    private void extract(){
        try{
            mainF.SetIconStat("working", this.StatElement);
            scraper.execute();
            if(scraper.getStatus()==Scraper.STATUS_FINISHED){
                this.Succeed=true;
                Map<String,Object> tmp=new HashMap<String,Object>();
                tmp.put("UpdateTime", ((Variable) scraper.getContext().get("UpdateTime")).toString().trim());
                Buffer.setVal(this.Result);
                mainF.SetIconStat("done", this.StatElement);
            }else{
                this.Succeed=false;
                this.Result=null;
                Buffer.setVal(null);
                mainF.SetIconStat("error", this.StatElement);
            }
        }catch(Exception ex){
            this.Succeed=false;
            this.Result=null;
            Buffer.setVal(null);
            mainF.SetIconStat("error", this.StatElement);
        }
    }

    public void run() {
        this.extract();
    }    
}

Ответы [ 3 ]

5 голосов
/ 06 ноября 2011

Если вы измените shutdown () на shutdownNow (), вы делаете правильные вещи в написанном вами коде. Но тогда, проверьте документацию shutdownNow ():

Нет никаких гарантий, кроме попыток изо всех сил остановить обработку активно выполняющие задачи. Например, типичные реализации будут отменить через Thread.interrupt (), поэтому любая задача, которая не отвечает на прерывания никогда не прекращаются.

Так что, вероятно, ваши T1 и T2 не кодируются правильно и не реагируют на прерывание достаточно хорошо. Можете ли вы скопировать код для них?

-

Исходя из вашего кода, я полагаю, что код, который занимает много времени, это scraper.execute (), верно? Так что внутри этого метода вы должны постоянно проверять что-то вроде этого:

if (Thread.interrupted()) {
   throw new InterruptedException();
}

Если приходит прерывание, InterruptedException будет выброшено и перехвачено в вашем операторе catch, и поток остановится.

4 голосов
/ 06 ноября 2011

Моя проблема с Future#cancel() заключается в том, что последующие вызовы get() выдают CancellationException. Иногда я все еще хочу иметь возможность вызвать get() на Future, чтобы получить частичный результат после завершения работы службы исполнителя. В этом случае можно реализовать логику завершения в вызовах, которые вы отправляете в службу executor. Используйте поле типа

private volatile boolean terminate;

public void terminate() {
    terminate = true;
}

и проверьте terminate в вызываемой программе так часто, как это требуется. Кроме того, вы должны где-нибудь вспомнить свои вызовы, чтобы вы могли звонить terminate() по всем из них.

1 голос
/ 06 ноября 2011

Используйте метод Executor. submit , он расширяет базовый метод Executor.execute (java.lang.Runnable), создавая и возвращая Future, который можно использовать для отмены выполнения и / или ожидания завершение:

task = Executor.submit( T1 )
...
task.cancel( true )
...