Java - SwingWorker - problem

I am developing a Java Desktop Application. This application performs the same task public class MyTask implements Callable<MyObject> {

on multiple threads at the same time.

Now when the user clicks the start button, I have created SwingWorker myWorker

and executed it.

Now this one myWorker

creates multiple instances MyTask

and sends them to ExecutorService

.

Each instance MyTask

has a loop and generates an intermediate result on each iteration. Now I want to collect these intermediate results from each instance MyTask

as soon as they are generated. Then, after collecting these intermediate results from each instance MyTask

, I want to post it through SwingWorker.publish(MyObject)

so the progress is shown on the EDT.

Q1. How to implement this? Should I MyTask

subclass SwingWorker

instead Callable

to get intermediate results, because I think it Callable

only returns the final result.

Q2. If the answer is Q1. yes then can you give me a small example to show how I can get these intermediate results and populate them and then post them from the main one SwingWorker

?

Q3. If I cannot use SwingWorker

in this situation, then how to implement it?

+2


a source to share


3 answers


Have a look at ExecutorCompletionService <T> . It is an Executor who supplies a method take

to get the result of any completed task.

Update:



The extension SwingWorker

won't do what you want as it is specifically designed to offload EDT work to a background thread. You cannot use it to offload work from a background thread to other background threads. The calls SwingWorker.publish

result in the equivalent of a SwingUtilities.invokeLater

. The mechanism I am aware of does not work for doing the same from background thread to background thread. It is best to create MyTask

a link to Queue

and poll the SwingWorker.doInBackground

queue for intermediate results.

0


a source


A1 + A2 . Yatendra, is it necessary that your main SwingWorker

be the only one that transfers intermediate results to EDT

? If your tasks were also instances SwingWorker

, the main worker could delegate the response to send intermediate results back EDT

to them and just take care of the lifecycle 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 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.");
    }
}

      

Remember this is just a test, I know there are some ugly calls 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 But if your project requires another one ExecutorService

to schedule its task, I would implement a similar publishing mechanism to perform the communication between your Main Swing Worker thread and that task. While this seems repetitive, can you use it java.concurrent.ConcurrentQueue

to store intermediate results as they appear?

PS: I just noticed a few days ago, but there is an annoying bug in SwingWorkers that prevents the ExecutorService from caching unused threads .

0


a source


SwingWorker is also Future. As such, it has a get () method that can be used inside the done () method to get the result of doInBackground () when that method ends.

Thus, the construction becomes something like this:

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.
    }
  }
};

      

-1


a source







All Articles