Further Example: Multi-threaded task partitioning.
It is sometimes useful to parallelize a task with independent sub-tasks, by
assigning each sub-task to a thread. This can make the whole task finish
sooner, if multiple processors are involved. (This will be the case, if the sub-
tasks perform network traffic.) In interactive Java programs, multithreading is
also used to enable partial results from sub-tasks to be pushed through to the
end user, while slower sub-tasks continue to grind away.
The code below (based on an example from Doug Lea) shows a very simple
way to control the rendering of several pictures in such a way that each picture
is delivered to a displayer as soon as it's ready, but the original requester
blocks until all rendering is finished. Each sub-task is coded by an anonymous
implementation of Runnable which is at the heart of each thread.
public class GroupPictureRenderer {
private PictureRenderer renderer;
private PictureDisplayer displayer;
...
public Picture[] render(final byte[][] rawPictures)
throws InterruptedException {
Thread workers[] = new Thread[rawPictures.length];
final Picture results[] = new Picture[rawPictures.length];
// start one thread per rendering sub-task
for (int ii = 0; ii < rawPictures.length; ii++) {
final int i = ii; // capture ii for each new thread
Runnable work = new Runnable() {
public void run() {
results[i] = renderer.render(rawPictures[i]);
displayer.display(results[i]);
}
};
workers[i] = new Thread(work, "Renderer");
workers[i].start();
}
// all threads are running; now wait for them all to finish
for (int i = 0; i < workers.length; i++)
workers[i].join();
// give all the finished pictures to the caller, too:
return results;
}
}