Экземпляры 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();

Или что-то в вашей модели данных однопоточно и блокирует второй поток? В этом случае вам придется решить эту проблему с помощью модели данных.