2010-05-08 2 views
2

Я занимаюсь разработкой приложения для настольных компьютеров Java. Это приложение выполняет одну и ту же задачу public class MyTask implements Callable<MyObject> { в нескольких потоках одновременно.Java - SwingWorker - problem

Теперь, когда пользователь нажимает кнопку «старт», я создали выполнил его.

Теперь этот myWorker создает несколько экземпляров MyTask и отправляет их в ExecutorService.

Каждый экземпляр MyTask имеет цикл и генерирует промежуточный результат на каждой итерации. Теперь я хочу собрать эти промежуточные результаты из каждого экземпляра MyTask, как только они будут сгенерированы. Затем, после сбора этих промежуточных результатов из каждого экземпляра MyTask, я хочу опубликовать его через SwingWorker.publish(MyObject), чтобы прогресс был показан на EDT.

Q1. Как это реализовать? Должен ли я сделать MyTask подкласс SwingWorker вместо Callable, чтобы получить промежуточные результаты, так как я думаю, что Callable возвращает окончательный результат.

Q2. Если ответ Q1. да, тогда вы можете дать мне небольшой пример, чтобы показать, как я могу получить эти промежуточные результаты и заполнить их, а затем опубликовать их из основного SwingWorker?

Q3. Если я не могу использовать SwingWorker в этой ситуации, то как это реализовать?

+0

Когда вы собираете промежуточные результаты из каждой задачи, вы хотите, чтобы все они были из одной и той же? То есть собрать все результаты итерации 1, тогда результаты итерации 2? – mdma

ответ

0

Посмотрите на ExecutorCompletionService<T>. Это Исполнитель, который поставляет метод take для получения результата любой завершенной задачи.

Update:

Расширение SwingWorker не будет делать то, что вы хотите, как она специально предназначена для разгрузки работы с EDT в фоновом потоке. Вы не можете использовать его для разгрузки работы из фонового потока в другие фоновые потоки. Звонки на SwingWorker.publish приведут к эквиваленту SwingUtilities.invokeLater. Механизм, о котором я знаю, не работает для того, чтобы делать то же самое из фонового потока в фоновый поток. Лучше всего создать MyTask со ссылкой на Queue и попросить SwingWorker.doInBackground опрос очереди для промежуточных результатов.

+0

Я хочу создать несколько 'SwingWorker' из одного' SwingWorker mainWorker'. Этот 'mainWorker' инициируется EDT. Причиной создания нескольких рабочих от основного работника является то, что я хочу собрать промежуточные результаты всех этих работников в «mainWorker», а затем публиковать промежуточные результаты через. 'publish (...)' метод 'mainWorker'. –

-1

SwingWorker также является Будущим. Таким образом, он имеет метод get(), который может использоваться внутри метода done() для получения результата doInBackground(), когда этот метод заканчивается.

Таким образом, конструкция становится несколько, как:

SwingWorker<T,P> sw=new SwingWorker<T,P>() { 

    @Override 
    public T doInBackground() throws Exception { 
    T result; 
    // do stuff here 
    return result; 
    } 

    @Override 
    public void done() { 
    try { 
     T result=get(); 
     // do stuff with result. 
    } 
    catch(ExecutionException e) { 
     Exception fromDoInBackground= (Exception) e.getCause(); 
     // handle exception thrown from doInBackground() 
    } 
    catch(InterruptedException i) { 
     // handle the case in which a SwingWorker was cancelled. typically: do nothing. 
    } 
    } 
}; 
+0

@user Я прошу вас сначала внимательно прочитать вопрос, прежде чем отвечать ... Я знаю, как использовать 'SwingWorker' уже. :) –

0

A1 + A2. Yatendra, необходимо ли, чтобы ваш главный SwingWorker был единственным, кто проголосовал бы за промежуточные результаты до EDT? Если ваши задачи были также SwingWorker экземпляров, Главный работник мог делегировать ответственность за отправку промежуточных результатов обратно в EDT им и просто заботиться о жизненном цикле TaskWorkers.

package threading; 

import java.util.LinkedList; 
import java.util.List; 

import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 

class MainSwingWorker extends SwingWorker<Void, Void> { 
    private List<TaskWorker> tasks; 

    public MainSwingWorker() { 
     tasks = new LinkedList<TaskWorker>(); 
     for(int i=0; i<2; i++) 
      tasks.add(new TaskWorker(i)); 
    } 

    @Override 
    public Void doInBackground() throws Exception { 
     Test.log("Building tasks.");      
     for(TaskWorker task : tasks) 
      launch(task); 
     Test.log("Waiting 5 secs."); 
     Thread.sleep(5000); 

     Test.log("Cancelling tasks"); 

     for(TaskWorker task : tasks) 
      task.cancel(true); 

     return null; 
    } 

    private void launch(final TaskWorker task) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       Test.log("Launching task worker."); 
       task.execute(); 
      } 
     });  
    } 
} 

class TaskWorker extends SwingWorker<Void, String> { 
    private int id; 

    public TaskWorker(int wid) { 
     id = wid; 
    } 

    @Override 
    public Void doInBackground() throws Exception {  
     System.out.format("[%s] Starting worker %s\n", Thread.currentThread().getName(), id); 
     while(!isCancelled()) { 
      // *************************** 
      // your task process code here 
      // *************************** 
      publish(String.format("A dummy interim result #%s", id)); 
      Thread.sleep(1000); 
     }  
     return null; 
    } 

    @Override 
    public void process(List<String> results) { 
     // it's pretty obvious, that once this method gets called you can safely 
     // call the Swing API from EDT among with the interim results 
     for(String result : results) 
      Test.log(result); 
    } 
} 

public class Test { 

    public static void log(String msg) { 
     System.out.format("[%s] %s\n", Thread.currentThread().getName(), msg); 
    } 

    public static void main(String[] args) throws Exception { 
     log("Init."); 
     SwingUtilities.invokeAndWait(new Runnable() { 
      @Override 
      public void run() { 
       log("Starting main worker."); 
       MainSwingWorker worker = new MainSwingWorker(); 
       worker.execute();       
      } 
     }); 
     Thread.sleep(7000); 
     log("Finished."); 
    } 
} 

Имейте вид, что это просто тест, я знаю, что есть несколько некрасивых Thread.sleep(long) звонков.

[main] Init. 
[AWT-EventQueue-0] Starting main worker. 
[SwingWorker-pool-1-thread-1] Building tasks. 
[SwingWorker-pool-1-thread-1] Waiting 5 secs. 
[AWT-EventQueue-0] Launching task worker. 
[AWT-EventQueue-0] Launching task worker. 
[SwingWorker-pool-1-thread-2] Starting worker 0 
[SwingWorker-pool-1-thread-3] Starting worker 1 
[AWT-EventQueue-0] A dummy interim result #1 
[AWT-EventQueue-0] A dummy interim result #0 
[AWT-EventQueue-0] A dummy interim result #0 
[AWT-EventQueue-0] A dummy interim result #1 
[AWT-EventQueue-0] A dummy interim result #1 
[AWT-EventQueue-0] A dummy interim result #0 
[AWT-EventQueue-0] A dummy interim result #0 
[AWT-EventQueue-0] A dummy interim result #1 
[AWT-EventQueue-0] A dummy interim result #0 
[AWT-EventQueue-0] A dummy interim result #1 
[SwingWorker-pool-1-thread-1] Cancelling tasks 
[main] Finished. 

A3 Но если иметь другой ExecutorService запланировать выполнение задания является обязательным в проекте, я бы реализовать подобный механизм опубликовывать-процесс для выполнения связи между главным Качелями Worker Thread, и этой задачей Thread , Хотя кажется, что он повторяется, вы можете использовать java.concurrent.ConcurrentQueue для хранения промежуточных результатов по мере их появления?

PS: Я только что заметил несколько дней назад, но есть раздражающая ошибка вокруг SwingWorkers, которая prevents its ExecutorService from caching unused threads.