Question

I'm working on a project that does some intense math calculations (arrays of matrices, vectors, etc.), so naturally I'm splitting the work into jobs, and submitting them to a CompletionService to perform the work in parallel.

Each of the job objects can fire events to notify applications when the job starts, ends, progresses, and/or fails.

Currently, each of the jobs receive a handle to the entire list of event listeners, and simply iterate through, passing an event object to each one (in the same thread). This doesn't sit well with me, so I'd like to get other peoples' experience with doing this sort of thing with custom events/listeners.

Should I send my events to the GUI thread? Some of the listeners may or may not be GUI-related, and I'd like to not force users of my code to have to manually send their events onto the GUI thread, something like the following:

public class MyFooEventListener implements FooEventListener {
    public void notifyJobStarted(FooEvent evt) {
        // I want to avoid having users of my library write the following, right?
        SwingUtilities.invokeLater(new Runnable(){
            // update GUI here.
        });
    }
}

I wouldn't mind writing my own EventQueue, as this is for a research project in school, and I suppose it would be a good exercise in concurrency. Just trying to figure out what the "proper" way of implementing an event-driven system is, how to properly fire events, etc. Links to articles/tutorials and howtos are also greatly appreciated.

Thanks!

EDIT:

My event model has multiple event types, such as JobStartedEvent, JobEndedEvent, JobProgressEvent, etc. Is this a bad approach? Should I have a single event type, and if so, how do I pass information to the listeners that is not common to all events? Example: I want to pass a double in the range [0-1] for the progress event, but that is not applicable for an event like JobFailureEvent. What's the best approach to handling this?

I could put the extra information in the "source" object itself, but my source objects are the Job objects themselves, and it doesn't sit well with me to "leak" references to the job object, especially while it is running:

FooJob jobObject = (FooJob)event.getSource();
int progressPercent = jobObject.getCurrentProgress() * 100;
progressLabel.setText(progressPercent + "%");
Was it helpful?

Solution

No. Emit your events on whatever thread needs to raise them and leave it up to the users of your subsystem to decide how they wish to handle them. If they wish to message the results to a GUI, fine, if not, they can do whatever they want, eg. queue them to another thread. Just document 'Events are raised on an internal thread and event handlers must not block'.

Anything else puts constraints on users that they may well not want, as you say.

OTHER TIPS

there are many ways to distribute events, each with their own pros and cons. if the consumer is not necessarily the GUI, then you definitely should not tie yourself to the awt EDT. unless you know for sure how the event consumers are going to work i would start simple and go from there. simple being: synchronously notify each consumer. if that ends up delaying the main task, then you should think about asynchronous notification. if the consumer is ultimately the GUI, then the consumer's notification method should be responsible for calling SwingUtilities.invokeLater.

Only threads that directly impact the GUI should be on the EDT. If you have other threads you need synchronized, just use the synchronized keyword (either on the method or on an object)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top