Как прекратить текущее выполнение кварцевого задания с помощью переопределенного метода прерывания, поступающего из интерфейса InterruptableJob? - PullRequest
2 голосов
/ 11 апреля 2020

У меня есть несколько кварцевых заданий для обработки некоторых данных. Я использовал интерфейс InterruptableJob при написании этих работ. Я должен добавить функцию прерывания к этим работам. Когда пользователь нажимает кнопку завершения, этот метод вызывает:

@Override
protected void immediatelyTerminate() {

    try {

        String fireInstanceIdToKillJob = "";

        Scheduler scheduler = schedulerFactory.getScheduler();
        List<JobExecutionContext> currentlyExecutingJobs = scheduler.getCurrentlyExecutingJobs();

        for(JobExecutionContext jec : currentlyExecutingJobs) {
            if(jec.getJobDetail().getKey().getName().contains(specificJobKey) {
                fireInstanceIdToKillJob = jec.getFireInstanceId();
            }
        }

        scheduler.interrupt(fireInstanceIdToKillJob);

    } catch (Exception e) {
        logger.debug("error in immediatelyTerminate() method:" + e);
    }
}

scheduler.interrupt вызывает метод interrupt (), который переопределяется в классе, и этот класс также имеет метод execute. Класс, который переопределил метод прерывания, выглядит следующим образом:

private Thread threadToKill;

@Override
public void execute() {
  threadToKill = Thread.currentThread();
}

@Override
public void interrupt() throws UnableToInterruptJobException {
    try {
        threadToKill.interrupt();
    } catch (Exception e) {
        System.out.println("Exception handled "+e);
    }   
}

Но с этим кодом задание не завершается, оно продолжает работать. threadToKill.interrupt (); строка на самом деле не завершает текущее задание.

Как я могу прекратить выполнение заданий?

1 Ответ

0 голосов
/ 24 апреля 2020

Мне пришлось реализовать эту самую функциональность пару лет go.

Прерывание потока не убивает его и не останавливает . Он просто активирует флаг, чтобы поток знал, что попросили остановиться. Большинство внутренних методов проверяют это и выдают InterruptedException, чтобы вы могли его поймать, но некоторые потоки с радостью игнорируют любые запросы на прерывание.
Итак, сама задача - определить этот сценарий и действовать соответствующим образом.

По сути, ваш метод interrupt() должен установить какой-либо флаг на true, и ваша работа должна время от времени проверять этот флаг и останавливать все, что делает, когда замечает, что флаг активен.
Вот как Я реализовал это:

public clas SomeJob implements InterruptableJob {

    protected AtomicBoolean stopFlag = new AtomicBoolean(false);

    @Override
    public void execute(final JobExecutionContext context) {
        for (Item item : listOfItems) { // whatever long tasks(s) you are doing,
            if (stopFlag.get()) {       // just check for this on every main loop
                logger.error("Job interrupted! Leaving at item: "+item);
                break;
            }
            performTask(item);
        }
        cleanUp();
        return;
    }

    private void performTask(Item item) {
        for(....) {               // another loop,
            if (stopFlag.get()) { // another check
                // ....
                return; // or break, depending on each case
            }
            someInternalProcessing(...);
        }
    }

    @Override
    protected void interrupt() {
        stopFlag.set(true);
    }
}

Вот и все. Просто убедитесь, что вычистили, закройте соединения и т.д. перед прерыванием.

...