Problem:
How to use Java Single Thread Executor? In this post we’ll show how the ExecutorService nicely executes jobs in order.
Solution:
As usually, java.util.concurrent.Excutors has two methods to create Single Threaded Executor:
- ExecutorService newSingleThreadExecutor()
Creates an executor with single worker thread. - ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) Creates an executor with single worker thread and allows to specify own ThreadFactory.
In the following example we’ll use the Executor to run a number of print jobs. As we’ve got only one printer and the driver is not thread-safe, we’re going to run jobs sequentially thanks to the executor:
package com.farenda.java.util.concurrent; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import static java.util.concurrent.TimeUnit.MILLISECONDS; public class SingleThreadExecutorExample { private static class PrinterJob implements Runnable { private static int nth = 0; private final int id = ++nth; private final int speed; public PrinterJob() { // draw 0-99 and give +1 to progress at least by 1%: this.speed = new Random().nextInt(99) + 1; } @Override public void run() { System.out.println("Starting printer work: " + id); for (int i = 0; i <= 100; i += speed) { try { MILLISECONDS.sleep(300); } catch (InterruptedException e) { // ignore } System.out.printf("worker %d, done %d%%%n", id, i); } System.out.println("Done PrinterJob: " + id); } } public static void main(String[] args) { System.out.println("Starting Single Thread Executor"); ExecutorService executor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; ++i) { executor.execute(new PrinterJob()); } executor.shutdown(); } } [/sourcecode] <p> And here's sample output of running the above program: </p> Starting Single Thread Executor Starting printer work: 1 worker 1, done 0% worker 1, done 59% Done PrinterJob: 1 Starting printer work: 2 worker 2, done 0% worker 2, done 24% worker 2, done 48% worker 2, done 72% worker 2, done 96% Done PrinterJob: 2 Starting printer work: 3 worker 3, done 0% worker 3, done 10% worker 3, done 20% worker 3, done 30% worker 3, done 40% worker 3, done 50% worker 3, done 60% worker 3, done 70% worker 3, done 80% worker 3, done 90% worker 3, done 100% Done PrinterJob: 3 Starting printer work: 4 worker 4, done 0% worker 4, done 62% Done PrinterJob: 4 Starting printer work: 5 worker 5, done 0% worker 5, done 25% worker 5, done 50% worker 5, done 75% worker 5, done 100% Done PrinterJob: 5
The executor runs only one task at a time, in one worker thread. All tasks are run in the order of submission. Not blazing fast, but does the work in a separate thread and we don’t have to worry about synchronization!