Предотвращение блокировки графического интерфейса Swing во время фоновой задачи

StackOverflow https://stackoverflow.com/questions/940913

Вопрос

У меня есть приложение Swing, в котором хранится список объектов.Когда пользователи нажимают кнопку,

Я хочу выполнить две операции над каждым объектом в списке, а затем, как только это будет завершено, отобразить результаты в JPanel.Я пробовал SwingWorker, Callable & Runnable выполнить обработку, но независимо от того, что я делаю, во время обработки списка (которая может занять до нескольких минут, поскольку он привязан к вводу-выводу), графический интерфейс блокируется.

У меня такое ощущение, что это, вероятно, способ вызова потоков или что-то в этом роде, или это может быть связано с функцией построения графиков?Это не резьбовое соединение, так как это очень быстро.

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

while(x.isAlive())  
{  
        Thread.sleep(1000);  
}

чтобы попытаться обеспечить это, но я боюсь, что это может быть причиной и моей проблемы.

Я повсюду искал подсказки, но, поскольку не могу их найти, я уверен, что делаю здесь что-то глупое.

Это было полезно?

Решение

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

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

Некоторые распространенные способы сделать это — использовать таймеры или SwingWorker.

А Учебники по Java есть много информации об этих вещах на уроке параллелизма.

Чтобы первая задача завершилась раньше второй, просто поместите их обе в один поток.Таким образом, вам не придется беспокоиться о правильном синхронизации двух разных потоков.

Вот пример реализации SwingWorker для вашего случая:

public class YourTaskSwingWorkerSwingWorker extends SwingWorker<List<Object>, Void> {
    private List<Object> list
    public YourClassSwingWorker(List<Object> theOriginalList){
        list = theOriginalList;
    }

    @Override
    public List<Object> doInBackground() {
        // Do the first opperation on the list
        // Do the second opperation on the list

        return list;
    }

    @Override
    public void done() {
        // Update the GUI with the updated list.
    }
}

Чтобы использовать этот код, при возникновении события для изменения списка создайте новый SwingWorker и скажи, чтобы началось.

Другие советы

Вы неправильно возвращаете качающуюся нить.Я понимаю, что вы используете callable/runnable, но я предполагаю, что вы делаете это неправильно (хотя вы не опубликовали достаточно кода, чтобы знать наверняка).

Базовая структура будет такой:

swingMethod() { // Okay, this is a button callback, we now own the swing thread
    Thread t=new Thread(new ActuallyDoStuff());
    t.start();
}

public class ActuallyDoStuff() implements Runnable {
    public void run() {
        // this is where you actually do the work
    }
}

Это просто пришло мне в голову, но я предполагаю, что вы либо не выполняете thread.start, а вместо этого вызываете метод run напрямую, либо вы делаете что-то еще в первом методе, который блокирует его ( например, thread.join).Ни один из них не освободит нить качания.Первый метод ДОЛЖЕН завершиться быстро, метод run() может занять столько времени, сколько захочет.

Если вы выполняете thread.join в первом методе, то поток НЕ возвращается в систему!

Редактировать:(Второе редактирование на самом деле) Я думаю, чтобы поговорить с проблемой, которую вы на самом деле чувствуете-вы можете захотеть больше думать с точки зрения системы модели/представления/контроллера.Код, который вы пишете, является контроллером (представлением обычно считаются компоненты на экране: представление/контроллер обычно очень тесно связаны).

Когда ваш контроллер получает событие, он должен передать работу вашей модели.Тогда вид теряется.Он не ждет модели, он просто делается.

Когда ваша модель будет завершена, ей нужно будет указать контроллеру сделать что-то еще.Это делается с помощью одного из методов вызова.Это передает управление обратно контроллеру, и вы продолжаете свой веселый путь.Если подумать об этом таким образом, разделение управления и намеренная передача его туда и обратно не кажется таким уж громоздким, и на самом деле это очень распространено.

Похоже, проблема может заключаться в том, что вы ожидаете завершения потоков изнутри потока графического интерфейса.Ваш поток GUI не должен ждать этих потоков, вместо этого вы должны заставить рабочие потоки вызывать некоторый метод в потоке GUI, который устанавливает флаг.Когда оба флага установлены, вы знаете, что оба потока завершены, и можете построить график.

Я не могу говорить о модели качающейся резьбы, но:

Мне тоже нужно выполнить два этапа обработки по порядку, так как лучше всего гарантировать, что второй этап дождется первого?

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

Решением моей проблемы стала смесь ответов jjnguy и Билла К., так что большое спасибо за это, ребята.Мне нужно было использовать потоки внутри SwingWorker следующим образом:

public class Worker extends SwingWorker<Void, Void>   
{  
    private List<Object> list;  
    public YourClassSwingWorker(List<Object> theOriginalList){  
        list = theOriginalList;  
    }

    @Override
    public List<Object> doInBackground() {
        Thread t = new Thread(new ProcessorThread(list));  
        t.start();
    }

    @Override
    public void done() {
        // draw graph on GUI
    }
}  
class ProcessorThread implements Runnable {  
    //do lots of IO stuff  
    Thread t2 = new Thread(new SecondProcess());
    t2.start();  
}

Это гарантировало, что вся работа выполняется рабочими потоками вне графического пользовательского интерфейса, а также гарантировало, что сам SwingWorker не выполняет всю работу, что могло быть проблемой.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top