Экземпляры Swingworker не работают одновременно
Мой компьютер имеет 4 ядра, и я запускаю программу Java swing gui. Когда я запускаю приложение, он использует только два ядра и около 30% загрузки процессора. У меня есть большое количество файлов для обработки и вы хотите разбить их на два потока, чтобы ускорить выполнение этой задачи с использованием большего количества процессоров.
У меня есть класс SwingWorker под названием PrepareTask, у которого есть конструктор с двумя ints:
class PrepareTask extends SwingWorker<Void, Void> {
int start, end;
PrepareTask (int start, int end) { ... }
...
public Void doInBackground() {... }
public void done() { ... }
Я создаю два примера этого типа:
PrepareTask prepareTask = new PrepareTask(0,numberOfFiles/2);
prepareTask.execute();
PrepareTask prepareTask2 = new PrepareTask(numberOfFiles/2, numberOfFiles);
prepareTask2.execute();
Оба запускаются (появляется), но когда они запускаются, я вижу (печатать stmts), что первая подготовка должна заканчивать (печатать stmts внутри) до начала второго. И загрузка процессора такая же, как и раньше, около 30%. Они оба, конечно, захватывают данные из того же источника, DefaultTableModel.
Любые идеи о том, как это сделать или что я делаю неправильно?
спасибо.
Ответы
Ответ 1
Это результат изменения поведения SwingWorker от одного обновления Java 6 до другого. На самом деле есть отчет об ошибке в старой базе данных SUN для Java 6.
Что произошло, SUN изменил исходную реализацию SwingWorker на использование N потоков, используя 1 поток с неограниченной очередью. Поэтому вы не можете одновременно запускать два SwingWorkers. (Это также создает сценарий, в котором может возникнуть взаимоблокировка: если один swingworker ждет другого, ожидающего первого, одна задача может в итоге выйти в тупик.)
Что вы можете сделать, чтобы обойти это, использовать ExecutorService и опубликовать на нем FutureTasks. Они обеспечат 99% SwingWorker API (SwingWorker - это производная FutureTask), все, что вам нужно сделать, - это правильно настроить своего Исполнителя.
Ответ 2
Возможно, Swing контролирует планирование ваших потоков? Или, может быть, SwingWorker имеет размер пула потоков 1 (в SwingWorker javadoc нет описания работы нескольких потоков SwingWorker, и я думаю, что несколько потоков могут вызвать некоторые трудные проблемы concurrency в Swing).
Если все, что вы хотите сделать, это запустить некоторую обработку параллельно,
вы можете решить этот простой способ, расширив
Java Thread
, реализующий run
, вызов SwingUtilities.invokeLater()
в
конец обновления GUI с любыми изменениями:
class PrepareTask extends Thread
{
PrepareTask (int start, int end) { ... }
public void run() { ... ; SwingUtilities.invokeLater(new Runnable() { public void run() { do any GUI updates here } )}
запустите потоки с помощью:
prepareTask.start();
Или что-то в вашей модели данных однопоточно и блокирует второй поток?
В этом случае вам придется решить эту проблему с помощью модели данных.