Как выполнять фоновые вычисления в асинхронном потоке (в веб-службе REST)

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

Я попробовал следующий метод, основанный на моем собственном понимании концепции потоков. Но в обоих случаях ответ HTTP возвращается сразу после выполнения фоновых вычислений, поэтому в основном поток вычислений и исходный поток не являются асинхронными, и поток вычислений останавливает поток ответа до завершения анализа.

  1. Запущен поток демона. Я ожидал, что поток демона будет работать в фоновом режиме, пока метод HTTP отправляет ответ. Но неправда. Ответ отображается только после выполнения вычисления в этом потоке. Разве потоки демона не должны работать в фоновом режиме, даже когда родительский поток завершает работу? (Пожалуйста, прочитайте комментарии Джеймса, чтобы узнать, как запуск демона мог быть здесь проблемой)

    Callable<Boolean> computeCallable = new CallableComputeProcess();
    Thread t=new Thread(computeCallable);
    t.setDaemon(true);
    t.start();

P.S. Вычислительный поток — это дочерний поток, который я создал внутри родительского потока.

Есть ли способ асинхронно запустить поток, который позволяет фоновым вычислениям просто выполняться в фоновом режиме, не останавливая ответ http?


person Vineeth Chitteti    schedule 16.02.2017    source источник
comment
Re, я ожидал, что поток демона... Но... Если вы хотите, чтобы кто-то объяснил, почему ваш код сделал то, что он сделал, вам придется показать нам код.   -  person Solomon Slow    schedule 16.02.2017
comment
Конечно, @jameslarge. Добавление кода в одно мгновение.   -  person Vineeth Chitteti    schedule 16.02.2017
comment
Re, Запустил поток демона. Если это означает, что вы позвонили t.setDaemon(), то, вероятно, это плохая идея. В терминологии Java поток демона — это поток, который будет автоматически уничтожен, если в программе не останется других потоков, не являющихся демонами. Вы, вероятно, не хотите, чтобы поток автоматически уничтожался, пока он выполняет полезные вычисления. Вы должны вызывать setDaemon() только в том случае, если единственной целью потока является предоставление некоторых услуг другим потокам.   -  person Solomon Slow    schedule 16.02.2017
comment
поток демона — это поток, который будет автоматически уничтожен, если в программе не останется других потоков, не являющихся демонами. Спасибо за информацию @jameslarge. Это было бы большой ошибкой, даже если бы это сработало. XD   -  person Vineeth Chitteti    schedule 16.02.2017


Ответы (2)


Для большей гибкости попробуйте rxJava:

Flowable.fromCallable(() -> {
    Thread.sleep(1000); //  imitate expensive computation
    return "Done";
})
  .subscribeOn(Schedulers.io())
  .observeOn(Schedulers.single())
  .subscribe(System.out::println, Throwable::printStackTrace);

https://github.com/ReactiveX/RxJava

person dres    schedule 17.02.2017
comment
Спасибо @dres. Это может занять некоторое время, так как проект находится на Java 1.7 :) - person Vineeth Chitteti; 18.02.2017
comment
это будет то же самое, что и в примере, за исключением отсутствия лямбды. просто создайте новый анонимный вызываемый объект. - person dres; 18.02.2017

Отвечая на мой собственный вопрос:

Я использовал концепцию FutureTask и ExecutorService, для которых я никогда не вызываю метод get(). Поскольку мы знаем, что фокус не смещается в поток (с FutureTask), пока мы не вызовем метод FutureTask.get(). Поскольку я никогда не вызывал метод get(), поток вычислений работает в фоновом режиме, тем временем возвращая ответ HTTP. И он продолжает работать в фоновом режиме, пока вычисления не закончатся.

ExecutorService executor = Executors.newFixedThreadPool(1);

Callable<Boolean> computeCallable = new CallableComputeProcess();

executor.submit(scimCallable);

И CallableComputeProcess выглядит так:

public class CallableComputeProcess implements Callable<Boolean> {
public Boolean call() {
        //do computation
        return true;
    }
}

Это не останавливает/не мешает основному потоку, который выполняет ответ и работает в фоновом режиме.

person Vineeth Chitteti    schedule 16.02.2017