What Happens When a Thread in a Java ThreadPool Throws an Exception?

This article experimentally compares how a Java ExecutorService thread pool reacts to uncaught exceptions when tasks are submitted via execute versus submit, showing that execute removes the faulty thread and creates a new one while submit retains the thread and stores the exception in a Future.

JD Tech Talk
JD Tech Talk
JD Tech Talk
What Happens When a Thread in a Java ThreadPool Throws an Exception?

1. Problem Overview

When a thread inside a java.util.concurrent.ExecutorService thread pool throws an uncaught exception, the pool's reaction differs depending on whether the task was submitted with execute or submit. The article investigates this behavior through source‑code verification and analysis.

2. Code Verification – execute

public class ThreadPoolExecutorDeadTest {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = buildThreadPoolExecutor();
        executorService.execute(() -> exeTask("execute"));
        executorService.execute(() -> exeTask("execute"));
        executorService.execute(() -> exeTask("execute-exception"));
        executorService.execute(() -> exeTask("execute"));
        executorService.execute(() -> exeTask("execute"));
        Thread.sleep(5000);
        System.out.println("再次执行任务=======================");
        executorService.execute(() -> exeTask("execute"));
        executorService.execute(() -> exeTask("execute"));
        executorService.execute(() -> exeTask("execute"));
        executorService.execute(() -> exeTask("execute"));
        executorService.execute(() -> exeTask("execute"));
    }

    public static ExecutorService buildThreadPoolExecutor() {
        return new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1000), new ThreadFactoryBuilder().setNameFormat("test-%s").build(),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    private static void exeTask(String name) {
        String printStr = "[thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "]";
        if ("execute-exception".equals(name)) {
            throw new RuntimeException(printStr + ", 我抛异常了");
        } else {
            System.out.println(printStr);
        }
    }
}

The execution result (shown in the image) displays a stack trace for the exception. After the exception, the pool removes the faulty worker thread and creates a new one to keep the pool size.

3. Code Verification – submit

public class ThreadPoolExecutorDeadTest {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = buildThreadPoolExecutor();
        executorService.submit(() -> exeTask("execute"));
        executorService.submit(() -> exeTask("execute"));
        executorService.submit(() -> exeTask("execute-exception"));
        executorService.submit(() -> exeTask("execute"));
        executorService.submit(() -> exeTask("execute"));
        Thread.sleep(5000);
        System.out.println("再次执行任务=======================");
        executorService.submit(() -> exeTask("execute"));
        executorService.submit(() -> exeTask("execute"));
        executorService.submit(() -> exeTask("execute"));
        executorService.submit(() -> exeTask("execute"));
        executorService.submit(() -> exeTask("execute"));
    }

    public static ExecutorService buildThreadPoolExecutor() {
        return new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1000), new ThreadFactoryBuilder().setNameFormat("test-%s").build(),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    private static void exeTask(String name) {
        String printStr = "[thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "]";
        if ("execute-exception".equals(name)) {
            throw new RuntimeException(printStr + ", 我抛异常了");
        } else {
            System.out.println(printStr);
        }
    }
}

The result image shows that no stack trace is printed. The exception is captured inside the Future returned by submit, and the worker thread remains in the pool; no new thread is created.

4. Source Code Analysis

Key methods examined:

java.util.concurrent.AbstractExecutorService#submit(java.lang.Runnable)

– wraps the runnable in a FutureTask, which catches any thrown exception and stores it. java.util.concurrent.ThreadPoolExecutor#runWorker – the core loop that executes tasks; uncaught exceptions cause the worker to exit. java.util.concurrent.ThreadPoolExecutor#processWorkerExit – invoked when a worker terminates; if the termination was due to an exception, the pool removes the thread and may create a replacement.

Because submit uses FutureTask, the exception is considered handled, so processWorkerExit does not treat it as a fatal worker failure. In contrast, execute runs the runnable directly, so an uncaught exception propagates out of runWorker, triggering thread removal.

5. Conclusions

When a task submitted with execute throws an uncaught exception, the pool logs the stack trace, removes the offending thread, and creates a new thread to maintain the configured pool size.

When a task submitted with submit throws an exception, the exception is captured inside the returned Future; the worker thread stays alive, no new thread is created, and the exception can be retrieved via Future.get().

Both submission methods allow other tasks in the pool to continue executing normally.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaconcurrencyException HandlingThreadPoolExecutorService
JD Tech Talk
Written by

JD Tech Talk

Official JD Tech public account delivering best practices and technology innovation.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.