2016-03-01 4 views
0

Рассмотрим этот код:Как остановить продолжительный функцию

class Solver { 

    private boolean abort = false; 

    public void solve(List<Case> cases) { 
     while(!abort) { 
      for(Case c : cases) 
       compute(c); // method that take too long to finish 
     } 
    } 

    // a bunch of methods 

    public void abort() { 
     abort = true; 
    } 
} 

// in another class 
Solver solver = new Solver(); 
solver.solve(cases); 

public void onSolveAborted() { 
    solver.abort(); 
} 

Как я могу изменить это решение, так что я могу прервать функцию решить мгновенно. Я знаю, что могу реализовать интерфейс Runnable в классе Solver, чтобы я мог остановить поток. Это приведет к большим изменениям в нашем коде, и я не знаю, позволяет ли используемая среда разрешить создание потоков.

ответ

0

ли Somthing как этот

Пусть говорит, у вас есть 100 случаев, 10 было решено, и вы хотите, чтобы прервать remaing 90. В коде, вы решаете все случаи в одной итерации, после этого времени проверка цикла для прерывания.

public void solve(List<Case> cases) { 
    Iterator<Case> iterator = cases.iterator(); 
    while (iterator.hasNext() && !abort) { 
     Case c=iterator.iterator.next(); 
     compute(c); 
    } 
} 
1

Это будет невозможно без использования резьбы. Что-то должно установитьabort() перед тем, как бегущая нить остановится. Взгляните на этот пример:

class Solver implements Runnable { 
    private List<Case> cases; 

    public Solver(List<Case> cases) { 
     this.cases = cases; 
    } 

    private void compute(Case c) { 
     try { 
      // Do some computation here 
     } finally { 
      // Sound the horns! Abandon ship! 
     } 
    } 

    public void solve(List<Object> cases) { 
     for (Case c : cases) { 
      try { 
       compute(c); // method that take too long to finish 
      } catch (InterruptedException e) { 
       // Hmm, maybe I should take the hint... 
       break; 
      } 
     } 
    } 

    public void run() { 
     solve(cases); 
    } 

    public static void main(String args[]) { 
     List<Case> cases = new ArrayList<Case>(); 

     // Populate cases 

     Thread t = new Thread(new Solver(cases)); 

     t.run(); 

     do { 
      // Wait 30 seconds 
      t.join(30 * 1000); 

      // Not done yet? Lets drop a hint.. 
      if(t.isAlive()) { 
       t.interrupt(); 
      } 
     } while (t.isAlive()); 
    } 
} 

Очень просто, он запускает решение в потоке. Основной поток ожидает до 30 секунд, затем прерывает метод solve. Метод solve ловит прерывание и изящно выходит из вычислений. В отличие от вашего решения с использованием boolean abort, это запускает InterruptedException из любого места вашего кода thead (и вы должны иметь дело с этим исключением), позволяя вам остановить выполнение в любое время.

Если вы хотите большего контроля, вы можете добавить try.. catch внутри compute, так что вы можете иметь предложение finally, чтобы закрыть все открытые файлы или еще что-то еще. Возможно, еще лучше, чтобы вычислить try.. finally, чтобы справиться с закрытием вещей «хорошим» способом и try.. catch (InterruptedException) в методе solve для обработки того, что происходит в случае прерывания (короче говоря, логика очистки и логика прерывания не должны быть в том же методе).

0

Измените свой класс на Runnable и используйте ExecutorService для его запуска. Затем вы можете просто использовать методы «shutDown()» или «shutDownNow()». Это чище и менее навязчиво, чем то, что вы предложили в своем собственном вопросе. Плюс убивающая нить вручную представляет собой идею REALLY BAD. В какой-то момент сам JDK в поточном методе «kill()» был убит, поскольку нет чистого способа сделать это правильно

+1

[shutdown()] (https://docs.oracle.com/javase/8/docs /api/java/util/concurrent/ExecutorService.html#shutdown--) делает не что иное, как предотвращение запуска новых задач и оставление текущих потоков, выполняемых как они есть, и [shutdownNow()] (https://docs.oracle.com /javase/8/docs/api/java/util/concurrent/ExecutorService.html#shutdownNow--) просто вызывает прерывание при выполнении задач. Никто не предлагал ничего убить. – Neil

+0

Вы правы, но лучше использовать shutdownNow(), затем разобраться с ним в своем собственном коде, по существу изобретая колесо, написав собственный ExecutionService –

+0

True. Я, вероятно, использовал бы ExecutionService, если бы я хотел запускать каждый случай параллельно или что-то минимально сложнее, чем пример выше. Конечно, неплохая идея, чтобы предпочесть ее по теме. Однако логика прерывания в коде потока не изменилась. – Neil