Завершить поток, выполняющий собственный код

В моем приложении есть оболочка для некоторого нативного кода, который вызывается через мост JNI. Этот собственный код необходимо выполнять в отдельном потоке (параллельная обработка). Однако проблема в том, что код иногда «зависает», поэтому поток необходимо завершить «принудительно». К сожалению, я не нашел для этого «деликатного» метода: общий совет - сообщить коду в потоке, чтобы он завершился изящно, но я не могу сделать это с помощью этого собственного кода (который является кодом сторонних разработчиков).

Я использую Java Concurrent API для отправки задач:

Future<Integer> processFuture = taskExecutor.submit(callable);

try {
    result = processFuture.get(this.executionTimeout, TimeUnit.SECONDS).intValue();
}
catch (TimeoutException e) {
    // How to kill the thread here?
    throw new ExecutionTimeoutException("Execution timed out (max " + this.executionTimeout / 60 + "min)");
}
catch (...) {
    ... exception handling for other cases
}

Future # cancel () только прервет поток, но не завершит его. Поэтому я использовал следующий трюк:

class DestroyableCallable implements Callable<Integer> {

    private Thread  workerThread;

    @Override
    public Integer call() {
        workerThread = Thread.currentThread();

        return Integer.valueOf(JniBridge.process(...));
    }

    public void stopWorkerThread() {
        if (workerThread != null) {
            workerThread.stop();
        }
    }
}

DestroyableCallable callable = new DestroyableCallable();

Future<Integer> processFuture = taskExecutor.submit(callable);

try {
    result = processFuture.get(this.executionTimeout, TimeUnit.SECONDS).intValue();
}
catch (TimeoutException e) {
    processFuture.cancel(true);
    // Dirty:
    callable.stopWorkerThread();

    ThreadPoolTaskExecutor threadPoolTaskExecutor = (ThreadPoolTaskExecutor) taskExecutor;

    logger.debug("poolSize: " + threadPoolTaskExecutor.getPoolSize() + ", maxPoolSize:"
                    + threadPoolTaskExecutor.getMaxPoolSize() + ", activeCount:"
                    + threadPoolTaskExecutor.getActiveCount());
    }

    throw new ...;
}
catch (...) {
    ... exception handling for other cases
}

Вопросы / проблемы с этим кодом:

  • Это вообще правильный способ сделать это? Есть ли другие более элегантные альтернативы?
  • activeCount на исполнителе задачи не уменьшается, поэтому исполнитель задачи все еще «думает», что поток запущен
  • Мне пришлось добавить проверку workerThread! = Null в stopWorkerThread () , поскольку в некоторых случаях эта переменная оказалась нулевой .Я не могу понять, что это за случаи ...

Примечания:

  • Собственный код не использует файловые дескрипторы (сокеты). Все передается ему как блок данных и возвращается таким же образом.
  • Собственный код интенсивно загружает процессор. Несмотря на то, что он гарантирует завершение, это может занять много времени.

Bounty edit : Подход / предложение пересмотреть собственный код ясны, пожалуйста, не предлагайте его в своем ответе. Мне нужно решение / обходной путь на чистой Java.

7
задан dma_k 13 January 2012 в 22:52
поделиться