Экземпляры Swingworker не работают одновременно - PullRequest
11 голосов
/ 26 сентября 2011

Мой компьютер имеет 4 ядра, и я запускаю программу Java Swing Gui.Когда я запускаю свое приложение, оно использует только два ядра и около 30% загрузки процессора.У меня есть большое количество файлов для обработки, и я хочу разделить их на два потока, чтобы выполнить эту задачу быстрее, используя больше процессоров.

У меня есть класс SwingWorker с именем PrepareTask, в котором есть конструктор с двумя целыми числами:

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();

Оба запускаются (кажется), но когда он запускается, я вижу (print stmts), что первая подготовка должназакончите (напечатайте stmts внутри) до начала второго.И загрузка процессора такая же, как и раньше, около 30%.Они оба, конечно, получают данные из одного и того же источника, DefaultTableModel.

Есть идеи, как это сделать или что я делаю неправильно?спасибо.

Ответы [ 2 ]

16 голосов
/ 26 сентября 2011

Это результат изменения поведения SwingWorker с одного обновления Java 6 на другое.На самом деле в старой базе данных ошибок SUN для Java 6 есть отчет об ошибке.

Произошло то, что SUN изменил исходную реализацию SwingWorker с использования N потоков на использование 1 потока с неограниченной очередью.Поэтому вы больше не можете одновременно запускать два SwingWorker.(Это также создает сценарий, при котором может возникнуть тупик: если один работник-качель ожидает другого, который ждет первого, в результате одна задача может зайти в тупик.)

Что вы можете сделать, чтобы обойти это, - это использоватьExecutorService и опубликовать FutureTasks на нем.Это обеспечит 99% API SwingWorker (SwingWorker является производным FutureTask), все, что вам нужно сделать, это правильно настроить вашего исполнителя.

0 голосов
/ 26 сентября 2011

Может быть, Swing контролирует планирование ваших потоков? Или, может быть, SwingWorker имеет размер пула потоков 1 (в javadoc SwingWorker нет описания работы нескольких потоков SwingWorker, и я полагаю, что несколько потоков могут вызвать некоторые проблемы с параллелизмом в 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();

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

...