2015-07-23 1 views
1

Я использую Java в течение нескольких лет, но знание потока - это мусор. Я довольно сильно искал Google и нашел хорошую информацию об общем использовании ProgressMonitorDialog, но ничего похожего на мои точные обстоятельства.Правильное использование кнопки отмены ProgressMonitorDialog, прерывание потоков и отображение прогресса

В настоящее время я использую ProgressMonitorDialog в качестве обертки вокруг экземпляра IRunnableWithProgress, который, в свою очередь, является оберткой вокруг Thread. Это работает нормально, но теперь я пытаюсь заставить кнопку cancel запускать прерывание на текущем потоке, которое я могу обработать, чтобы изящно завершить операцию.

Важно отметить, что у меня есть два плагина; «Данные» и «Пользовательский интерфейс». Плагин данных содержит всю реальную работу и должен быть независим от пользовательского интерфейса или любых плагинов Eclipse. Плагин UI должен быть как можно более тонким.

Вот дистиллированная версия кода, который я получил до сих пор.

данных:

public class Data { 
    public static Thread createThread() { 
     return new Thread() { 
      @Override 
      public void run() { 
       Thing t = new Thing(); 
       t.operationA(); 
       t.operationB(); 
       t.operationC(); 
      } 
     } 
    } 
} 

UI:

public class UI { 

    public void doOperation() { 
     try { 
      new ProgressMonitorDialog(getShell()).run(true, true, new MyOperation()); 
     } 
     catch (Exception e) { 
      e.printStatckTrace(); 
     } 
    } 

    public class MyOperation implements IRunnableWithProgress { 

     @Override 
     public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { 

      monitor.beginTask("Task", 2); 

      try { 
       Thread myThread = Data.createThread(); 
       myThread.start(); 
       monitor.worked(1); 

       while (myThread.isAlive() && !monitor.isCanceled()) {} 

       if (monitor.isCanceled()) { 
        myThread.interrupt(); 
       } 

       monitor.worked(1); 

      } 
      finally { 
       monitor.done(); 
      } 
     } 
    } 

} 

Итак, когда кнопка отмены нажата, myThread.interrupt() называется. Теперь поток должен реагировать на прерывание. Data.createThread() теперь выглядит примерно так:

public static Thread createThread() { 
    return new Thread() { 
     @Override 
     public void run() { 

      Thing t = new Thing(); 

      t.operationA(); 

      if (Thread.currentThread.isInterrupted()) { 
       // Tidy up 
       return; 
      } 

      t.operationB(); 

      if (Thread.currentThread.isInterrupted()) { 
       // Tidy up 
       return; 
      } 

      t.operationC(); 

      if (Thread.currentThread.isInterrupted()) { 
       // Tidy up 
       return; 
      } 
     } 
    } 
} 

Это может быть довольно многословен опросом прерванного состояния, как это, но я не могу видеть это вызывает какие-либо проблемы.

Но что, если Thing.operationA() не атомная, и может быть прервана в этой функции:

public class Thing { 
    public void operationA() { 
     atomic1(); 
     // How would I detect and handle a change to the interrupted state here? 
     atomic2(); 
    } 
    public void operationB() { 
     // One atomic operation 
    } 
    public void operationC() { 
     // One atomic operation 
    } 
} 

Как бы обнаруживать и обрабатывать изменения в прерванном состоянии между atomic1() и atomic2()? Это так же просто, как опрос Thread.currentThread.isInterrupted()? Или мне нужно передать около volatile объект для отслеживания прерванного состояния? Должен ли я бросать InterruptedException где-нибудь?

Мой второй вопрос касается отслеживания прогресса и отчетности. Я понимаю, как следует использовать IProgressMonitor.worked(). Как уже было видно, поток Data содержит 3 операции. Можно ли передавать эту информацию до пользовательского интерфейса, чтобы я мог отслеживать прогресс в ProgressMonitorDialog?

В идеале, что-то вроде этого:

public static Thread createThread() { 
    return new Thread() { 
     @Override 
     public void run(IProgressMonitor monitor) { 

      Thing t = new Thing(); 

      t.operationA(); 

      monitor.worked(1); 

      if (Thread.currentThread.isInterrupted()) { 
       // Tidy up 
       return; 
      } 

      t.operationB(); 

      monitor.worked(1); 

      if (Thread.currentThread.isInterrupted()) { 
       // Tidy up 
       return; 
      } 

      t.operationC(); 

      monitor.worked(1); 

      if (Thread.currentThread.isInterrupted()) { 
       // Tidy up 
       return; 
      } 
     } 
    } 
} 

Однако, как указано, данные могут не зависеть от Eclipse, и поэтому прохождение IProgressMonitor не работает в этом случае.

Могу ли я иметь отслеживание изменений в моем потоке, а затем асинхронно вызывать что-то вроде myThread.getProgress() из потока пользовательского интерфейса, чтобы обновить индикатор выполнения новой работой? Я не уверен, насколько это возможно (это появилось у меня в голове, когда я писал этот вопрос), поэтому я попытаюсь это сделать дальше.

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

ответ

1

Между atomic1() и atomic2() вам необходимо проверить на Thread.currentThread.isInterrupted() на очистку в случае отмены. Не нужно бросать исключение, если вы обрабатываете то, что необходимо.

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

+0

Спасибо, это полезная информация. Использование слушателя для отслеживания прогресса - отличная идея! – Nadz3k