Как завершить процесс Java из другого?

Я делаю решатель CSP, который вычисляет все комбинаторные решения конкретной задачи, подобной этой (кратко):

// Say we are in a Solver class
public void solve() {
  // find solution...
}

// This would be in a Problem class
problem.getSolver().solve();

Существует большая вероятность того, что процесс разрешения займет много времени, например, более пары минут. До сих пор, когда это занимало так много времени, я просто остановил процесс через консоль.

Но в конечном итоге я собираюсь опубликовать свое приложение как веб-приложение на хосте, который поддерживает приложения Java (побочный вопрос: я видел, что могу сделать это в Google Cloud, и мне также рассказали об AWS; они хорошие варианты?). Это означает, что я или пользователь больше не могу завершить процесс, если он займет слишком много времени.

Я хочу добавить функциональность возможности отмены процесса разрешения по желанию.

Поэтому я бы объявил новый метод в классе Solver, который завершит процесс, что фактически остановит процесс разрешения:

public void stopResolutionProcess() {
  // kill the process, therefore, stop the resolution process
}

Я не могу просто вызвать problem.getSolver().stopResolutionProcess() после того, как процесс разрешения уже запущен, потому что поток уже запущен, и пока этот процесс не завершится, вызов этого метода никогда не будет выполнен.

Так как же я мог это сделать? Как клиент может сигнализировать службе, размещенной в облаке, о завершении запущенного процесса?


person dabadaba    schedule 01.04.2016    source источник


Ответы (2)


Поместите длительный процесс в другой поток. При необходимости вы можете остановить его из основного потока. Видеть:

Как остановить поток другим потоком?

person stepanian    schedule 01.04.2016

Поскольку вы еще не выбрали облачный хост, на этот вопрос действительно сложно ответить. Вообще говоря, вам нужен объект синхронизации. Что-то вроде

volatile boolean keepRunning = true;

и ваш метод подойдет

public void stopResolutionProcess(){
    keepRunning = false;
}

то в вашем решении вы должны регулярно проверять эту переменную

public void solve(){
   while(keepRunning){
       // doSomething();
       Thread.sleep(500);
   }
}

Теперь я использую здесь переменную, но этого может быть недостаточно. В App Engine ваше приложение может работать в разных экземплярах, где статические переменные не синхронизированы. Вам понадобится объект синхронизации, доступный для всех ваших потоков решения. В App Engine это будет объект хранилища данных, который также кэшируется в кэше памяти. Но вы можете использовать Pub/Sub или другие механизмы для распространения выполнения задачи. Специфика тесно связана со средой, которую вы выберете для запуска.

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

person konqi    schedule 01.04.2016
comment
Это решение не сработает. Метод solve просто вызывает метод Choco solver.findSolution(). Это метод findSolution(), который потенциально может занять целую вечность. - person dabadaba; 01.04.2016
comment
Как я сказал. Это скорее общая проблема, и пример на самом деле является лишь отправной точкой того, как вы могли бы достичь этого в теории. На самом деле не имеет значения, где вы проверяете наличие флага. В AppEngine вы бы вообще не использовали потоки, вы бы использовали очереди задач и проверяли значение кэшированного хранилища данных, поэтому keepRunning фактически был бы методом, который запрашивает хранилище данных. - person konqi; 01.04.2016
comment
Для обеспечения безопасности потоков обязательно пометьте флаг keepRunning как volatile. - person Adam Michalik; 01.04.2016
comment
@AdamMichalik хорошо, я добавил volatile. Подход App Engine не будет использовать потоки, поэтому не будет необходимости в volatile. - person konqi; 01.04.2016