Я использую 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()
из потока пользовательского интерфейса, чтобы обновить индикатор выполнения новой работой? Я не уверен, насколько это возможно (это появилось у меня в голове, когда я писал этот вопрос), поэтому я попытаюсь это сделать дальше.
Здесь много информации и вопросительных знаков, извините, если мой стиль немного разбросан. Я мог бы разработать больше, если нужно, но это уже стена текста. Любая информация, советы или идеи оценены.
Спасибо, это полезная информация. Использование слушателя для отслеживания прогресса - отличная идея! – Nadz3k