Not all Java single-threaded executors are created equal: a Java finalizer horror story

The problem

// Get an executor
var executor = Executors.newFixedThreadPool(4);

// Do stuff

// Shut it down
static class FinalizableDelegatedExecutorService
extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
protected void finalize() {
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
new LinkedBlockingQueue<Runnable>()));

The fix, and a bit of caution

var executor = Executors.newSingleThreadExecutor();
var executor = Executors.newFixedThreadPool(1);
  1. Make sure that you manage executors correctly, and especially that you don’t forget to shut them down. This is especially important in test suites because you could be creating lots of them.
  2. As a general practice for new code I think it’s a good idea to call Executors.newFixedThreadPool(1), even if there's a method with the correct name for the purpose. At some point in future Java releasesfinalizers will be gone and Executors.newSingleThreadExecutor() will have the same runtime behavior, but meanwhile you can avoid some potential headaches.
  3. If you or your libraries use Executors.newSingleThreadExecutor() and you see weird task rejections then there's a good chance you hit the same problem!




Computer scientist. Hackademic. Does more with less.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Julien Ponge

Julien Ponge

Computer scientist. Hackademic. Does more with less.

More from Medium

An epic tale: comparing JDBC and R2DBC in a real-world scenario

Easy mass-logging with AspectJ maven plugin

Why is Java moving to Functional Programming ?

We Need Java