Экземпляры Swingworker не работают одновременно

Мой компьютер имеет 4 ядра, и я запускаю программу графического интерфейса Java Swing. Когда я запускаю свое приложение, оно использует только два ядра и около 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();

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

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


person rtfminc    schedule 25.09.2011    source источник
comment
Обратите внимание, что если большая часть времени обработки связана с доступом к файлам, то наличие большого количества потоков не обязательно ускорит ее, поскольку узким местом станет диск. Можете ли вы развить способ обработки, который вы выполняете с этими файлами?   -  person jfpoilpret    schedule 26.09.2011


Ответы (2)


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

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

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

person user268396    schedule 25.09.2011
comment
Я видел это заявление раньше, но вы резюмировали это лучше, чем большинство: +1 - person Hovercraft Full Of Eels; 26.09.2011
comment
И это должно быть исправлено в Java SE 6u21: oracle.com/technetwork/ java/javase/bugfixes6u21-156339.html - person keuleJ; 26.09.2011

Может быть, Swing контролирует планирование ваших потоков? Или, может быть, SwingWorker имеет размер пула потоков, равный 1 (в javadoc SwingWorker нет описания запуска нескольких потоков SwingWorker, и я предполагаю, что несколько потоков могут вызвать некоторые сложные проблемы параллелизма в Swing).

Если все, что вы хотите сделать, это запустить некоторую обработку параллельно, можете ли вы решить эту проблему простым способом, расширив класс Java Thread, внедрив run, вызвав SwingUtilities.invokeLater() в конце, чтобы обновить графический интерфейс с любыми изменениями:

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

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

person Simon C    schedule 25.09.2011