Support free tutorials:











vogella training Training Books



Eclipse Jobs and Background Processing - Tutorial

Lars Vogel

Version 3.2

26.03.2014

Revision History
Revision 0.1 - 3.2 12.07.2009 - 26.03.2014 Lars
Vogel
created, bug fixes and enhancements

Background processing in Eclipse Plug-ins

This tutorial describes how to do asynchronous work within Eclipse plug-ins and RCP applications. It explains the usage of the Jobs API for performing asynchronous tasks.

This tutorial can be used for Eclipse 3.x and Eclipse 4.x based plug-ins.


Table of Contents

1. Prerequisites for this tutorial
2. Eclipse background processing
2.1. Main thread
2.2. Using dependency injection and UISynchronize
2.3. Eclipse Jobs API
2.4. Priorities of Jobs
2.5. Blocking the UI and providing feedback
3. Asynchronous processing and the event bus
4. Reporting Progress
4.1. IProgressMonitor
4.2. Reporting progress in Eclipse RCP applications
5. Reporting Progress in Eclipse 3.x
6. Tutorial: Using Eclipse Jobs
7. Using syncExec() and asyncExec()
8. Learn more about Eclipse 4 RCP development
9. Support free vogella tutorials
9.1. Thank you
9.2. Questions and Discussion
10. Links and Literature
10.1. Eclipse Jobs resources
10.2. Source Code
10.3. vogella Resources

Get the book Eclipse IDE book

1. Prerequisites for this tutorial

This tutorial assumes what you have basic understanding of development for the Eclipse platform. Please see Eclipse RCP Tutorial or Eclipse Plug-in Tutorial if you need any basic information.

2. Eclipse background processing

2.1. Main thread

An Eclipse RCP application runs in one process but can create multiple threads.

By default the Eclipse framework uses a single thread to run all the code instructions. This thread runs the event loop for the application and is the only thread that is allowed to interact with the user interface (UI). It is called the main thread. Sometimes it is also called the UI thread, but this is a misnomer as it handles all events not only the ui events.

If another thread tries to update the UI, the Eclipse framework throws an SWTException exception.

org.eclipse.swt.SWTException: Invalid thread access 

All events in the user interface are executed one after another. If you perform a long running operation in the main thread, the application does not respond to user interaction during the execution time of this operation.

Blocking the user interaction is considered a bad practice. Therefore it is important to perform all long running operations in a separate thread. Long running operations are, for example, network or file access.

As only the main thread is allowed to modify the user interface, the Eclipse framework provides ways for a thread to synchronize itself with the main thread. It also provides the Eclipse Jobs framework which allows you to run operations in the background and providing feedback of the job status to the Eclipse platform.

2.2. Using dependency injection and UISynchronize

The org.eclipse.e4.ui.di plug-in contains the UISynchronize class. An instance of this class can be injected into an Eclipse application via dependency injection.

UISynchronize provides the syncExec() and asyncExec() methods to synchronize with the main thread.

2.3. Eclipse Jobs API

The Eclipse Jobs API provides support for running background processes and providing feedback about the progress of the Job.

The important parts of the Job API are:

  • IJobManager - schedules jobs

  • Job - the individual task to perform

  • IProgressMonitor - interface to communicate information about the status of your Job.

The creation and scheduling of a Job is demonstrated in the following code snippet.

// get UISynchronize injected as field
@Inject UISynchronize sync;

// more code

Job job = new Job("My Job") {
  @Override
  protected IStatus run(IProgressMonitor monitor) {
    // do something long running
    //... 
            
    // If you want to update the UI
    sync.asyncExec(new Runnable() {
      @Override
      public void run() {
        // do something in the user interface
        // e.g. set a text field
      }
    });
    return Status.OK_STATUS;
  }
};

// Start the Job
job.schedule(); 

If you want to update the user interface from a Job, you need to synchronize the corresponding action with the user interface similar to the direct usage of threads.

2.4. Priorities of Jobs

You can set the Job priority via the job.setPriority() method. The Job class contains predefined priorities, e.g. Job.SHORT, Job.LONG, Job.BUILD and Job.DECORATE.

The Eclipse job scheduler will use these priorities to determine in which order the Jobs are scheduled. For example, jobs with the priority Job.SHORT are scheduled before jobs with the Job.LONG priority . Check the JavaDoc of the Job class for details.

2.5. Blocking the UI and providing feedback

Sometimes you simply want to give the user the feedback that something is running without using threads.

The easiest way to provide feedback is to change the cursor via the BusyIndicator.showWhile() method call.

// Show a busy indicator while the runnable is executed
BusyIndicator.showWhile(display, runnable); 

If this code is executed, the cursor will change to a busy indicator until the Runnable is done.

3. Asynchronous processing and the event bus

Your threads can use the IEventBroker to send event data. Every listener will be automatically called and if you use the UIEventTopic annotation, this method is automatically called in the main thread.

private static final String UPDATE ="update";

// get the IEventBroker injected
@Inject
IEventBroker broker;

// somewhere in you code you do something 
// performance intensive

button.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent e) {
        Runnable runnable = new Runnable() {
          public void run() {
            for (int i = 0; i < 10; i++) {
              try {
                Thread.sleep(500);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
              // send out an event to update
              // the UI
              broker.send(UPDATE, i);
            }
          }
        };
        new Thread(runnable).start();
      }
    });



// more code
// ....


// get notified and sync automatically
// with the UI thread

@Inject @Optional
public void  getEvent(@UIEventTopic(UPDATE) int i) {
  // text1 is a SWT Text field
  text1.setText(String.valueOf(i));
  System.out.println(i);
} 

4. Reporting Progress

4.1. IProgressMonitor

The IProgressMonitor object can be used to report progress. Use the beginTask() method to specify the total units of work. Use the worked() method to report that a certain number of units of work have been finished. The worked() method is called with the units of work done since the last call, it is not called with the total amount of finished work. The usage of IProgressMonitor in a Job is demonstrated in the following code.

Job job = new Job("My Job") {
 @Override
 protected IStatus run(IProgressMonitor monitor) {
  // set total number of work units
  monitor.beginTask("Doing something time consuming here", 100);
  for (int i = 0; i < 5; i++) {
   try {
     // sleep a second
     TimeUnit.SECONDS.sleep(1);

     monitor.subTask("I'm doing something here " + i);

     // report that 20 additional units are done
     monitor.worked(20);
    } catch (InterruptedException e1) {
     e1.printStackTrace();
     return Status.CANCEL_STATUS;
    }
   }
  System.out.println("Called save");
  return Status.OK_STATUS;
  }
 };
job.schedule(); 

4.2. Reporting progress in Eclipse RCP applications

In Eclipse applications you can report progress by implementing the IProgressMonitor interface.

You can, for example, add a ToolControl to a toolbar in your application model. This ToolControl can implement the IProgressMonitor interface to show the process.

This is demonstrated in the following example.

package com.example.e4.rcp.todo.ui.composites;

import javax.annotation.PostConstruct;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ProgressBar;

public class MyToolControl implements IProgressMonitor {
  private ProgressBar progressBar;

  @Inject UISynchronize sync;
  
  @PostConstruct
  public void createControls(Composite parent) {
    progressBar = new ProgressBar(parent, SWT.SMOOTH);
    progressBar.setBounds(100, 10, 200, 20);
  }

  @Override
  public void worked(final int work) {
    sync.syncExec(new Runnable() {
      @Override
      public void run() {
        System.out.println("Worked");
        progressBar.setSelection(progressBar.getSelection() + work);
      }
    });
  }

  @Override
  public void subTask(String name) {

  }

  @Override
  public void setTaskName(String name) {

  }

  @Override
  public void setCanceled(boolean value) {

  }

  @Override
  public boolean isCanceled() {
    return false;
  }

  @Override
  public void internalWorked(double work) {
  }

  @Override
  public void done() {
    System.out.println("Done");

  }

  @Override
  public void beginTask(String name, int totalWork) {
    sync.syncExec(new Runnable() {
      @Override
      public void run() {
        progressBar.setMaximum(totalWork);
        progressBar.setToolTipText(name);
      }
    });
    System.out.println("Starting");
  }
} 

This new element can be accessed via the model service and used as an IProgressMonitor for the job.

// assumes the following injections:
// EModelService injected as "service" field
// MApplication injected as  "application" field

Job job = new Job("My Job") {
  // code as before
};

// setting the progress monitor
IJobManager manager = Job.getJobManager();

// ToolItem has the ID "statusbar" in the model
MToolControl element = (MToolControl) service.find("statusbar",
  application);

Object widget = element.getObject();
final IProgressMonitor p = (IProgressMonitor) widget;
ProgressProvider provider = new ProgressProvider() {
  @Override
  public IProgressMonitor createMonitor(Job job) {
    return p;
  }
};

manager.setProgressProvider(provider);
job.schedule(); 

Tip

A more advanced implementation could, for example, implement a progress monitoring OSGi Service and report progress to the user interface via the event service.

5. Reporting Progress in Eclipse 3.x

To activate progress reporting in the status line in Eclipse 3.x you have to activate progress reporting in preWindowOpen() method of the WorkbenchWindowAdvisor.

6. Tutorial: Using Eclipse Jobs

Create a new Eclipse plug-in project "de.vogella.jobs.first" with a View and a Button included in this View.

Create the following MySelectionAdapter class.

package de.vogella.jobs.first.parts;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class MySelectionAdapter extends SelectionAdapter {
  private final Shell shell;

  public MySelectionAdapter(Shell shell) {
    this.shell = shell;
  }

  @Override
  public void widgetSelected(SelectionEvent e) {
    Job job = new Job("First Job") {
      @Override
      protected IStatus run(IProgressMonitor monitor) {
        doLongThing();
        syncWithUi();
        // use this to open a Shell in the UI thread
        return Status.OK_STATUS;
      }

    };
    job.setUser(true);
    job.schedule();
  }

  private void doLongThing() {
    for (int i = 0; i < 10; i++) {
      try {
        // We simulate a long running operation here
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("Doing something");
    }
  }

  private void syncWithUi() {
    Display.getDefault().asyncExec(new Runnable() {
      public void run() {
        MessageDialog.openInformation(shell, "Your Popup ",
            "Your job has finished.");
      }
    });

  }
} 

Add an instance of MySelectionAdapter as SelectionListener to your Button.

Button button = new Button(parent, SWT.PUSH);
button.addSelectionListener(new MySelectionAdapter(shell)); 

To access the Shell in Eclipse 3.x you can use the getSite().getShell() method call. In Eclipse 4 you declare a field and let Eclipse inject the Shell.

@Inject Shell shell 

Start your application or the Eclipse workbench with your plug-in and press the Button. A dialog is opened.

7. Using syncExec() and asyncExec()

In Eclipse 3.x API based plug-ins you cannot use dependency injection to get the UISynchronize instance injected.

In this case you can use the Display class which provides the syncExec() and asyncExec() methods to update the user interface from another thread.

// Update the user interface asynchronously
Display.getDefault().asyncExec(new Runnable() {
  public void run() {
    // ... do any work that updates the screen ...
  }
});

// Update the user interface synchronously

Display.getDefault().syncExec(new Runnable() {
  public void run() {
    // do any work that updates the screen ...
    // remember to check if the widget
    // still exists
    // might happen if the part was closed
  }
}); 

8. Learn more about Eclipse 4 RCP development

I hope you enjoyed this tutorial. You find this tutorial and much more information also in the Eclipse 4 RCP book from this author.

9. Support free vogella tutorials

Maintaining high quality free online tutorials is a lot of work. Please support free tutorials by donating or by reporting typos and factual errors.

9.1. Thank you

Please consider a contribution if this article helped you.

Flattr this

9.2. Questions and Discussion

If you find errors in this tutorial, please notify me (see the top of the page). Please note that due to the high volume of feedback I receive, I cannot answer questions to your implementation. Ensure you have read the vogella FAQ as I don't respond to questions already answered there.

10. Links and Literature

10.2. Source Code

Source Code of Examples

10.3. vogella Resources

vogella Training Android and Eclipse Training from the vogella team

Android Tutorial Introduction to Android Programming

GWT Tutorial Program in Java, compile to JavaScript and HTML

Eclipse RCP Tutorial Create native applications in Java

JUnit Tutorial Test your application

Git Tutorial Put all your files in a distributed version control system