Skip to content

Instantly share code, notes, and snippets.

@wytten
Last active December 14, 2015 07:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wytten/5048011 to your computer and use it in GitHub Desktop.
Save wytten/5048011 to your computer and use it in GitHub Desktop.
Submit a number of tasks to be executed by a fixed-size thread pool, then be informed as each task is completed. Exit when all are complete.
*.class
*~
.project
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Demonstration of {@link java.util.concurrent} thread pooling capability.<br/>
* Submits a number of tasks to be executed by a fixed-size thread pool, then is informed as each task is completed.<br/>
* Exits when all are complete.
*/
public class CompletionServiceApp {
private static final int NUM_TASKS = 100;
private static final int NUM_THREADS = 4;
private static final ExecutorService POOL = Executors.newFixedThreadPool(NUM_THREADS);
private static final CompletionService<String> SERVICE = new ExecutorCompletionService<String>(POOL);
private static final Random RANDOM = new Random(System.currentTimeMillis());
public static void main(String[] args) throws InterruptedException, ExecutionException {
// submit the tasks
for (int i = 1; i <= NUM_TASKS; i++) {
SERVICE.submit(new StringTask(i));
}
// await their completion
int completedCount = 0;
while (completedCount < NUM_TASKS) {
// obtain the next completed result holder
Future<String> future = SERVICE.take();
assert future.isDone();
// get the result returned by the task's call() method
String result = future.get();
if (result == null) {
System.err.println("Failure detected");
continue;
}
// task completed; print the result
System.out.println(result);
completedCount++;
}
POOL.shutdown();
}
public static class StringTask implements Callable<String> {
private static final int MAX_DELAY = 1000;
private int taskNumber;
public StringTask(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public String call() throws Exception {
// random delay, simulating work being performed
long delay = 1 + Math.abs(RANDOM.nextLong() % MAX_DELAY);
Thread.sleep(delay);
// randomly introduce simulated failures
if (RANDOM.nextDouble() > 0.9) {
System.err.println("Simulated failure!");
// One might throw an Exception here (which would get wrapped in a ExecutionException)
// but unfortunately there is no easy way for the caller to know which particular task
// threw the exception. So taking the awkward step of having this task resubmit itself
// here, rather than have the caller do it, as one might expect.
SERVICE.submit(this);
return null;
}
return String.format("Task #%d slept for %dms serviced by thread %s", taskNumber, delay, Thread.currentThread()
.getName());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment