MST

星途 面试题库

面试题:Java线程池饱和策略对执行流程的影响

当Java线程池达到饱和状态时,不同的饱和策略(如AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy)是如何影响线程池后续执行流程的?请举例说明每种策略下线程池和任务的具体处理情况。
34.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. AbortPolicy(默认策略)
    • 策略描述:当线程池饱和且无法处理新任务时,抛出 RejectedExecutionException 异常。
    • 示例代码
import java.util.concurrent.*;

public class AbortPolicyExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                2, // 最大线程数
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1), // 任务队列容量为1
                new ThreadPoolExecutor.AbortPolicy());

        for (int i = 0; i < 4; i++) {
            int taskNumber = i;
            executor.submit(() -> {
                System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        executor.shutdown();
    }
}
  • 执行流程:线程池核心线程数和最大线程数都为2,任务队列容量为1。当提交第4个任务时,线程池和任务队列都已满,此时会抛出 RejectedExecutionException 异常,任务无法提交到线程池执行。
  1. CallerRunsPolicy
    • 策略描述:当线程池饱和时,将被拒绝的任务交由调用者线程来执行。
    • 示例代码
import java.util.concurrent.*;

public class CallerRunsPolicyExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                2, // 最大线程数
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1), // 任务队列容量为1
                new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 0; i < 4; i++) {
            int taskNumber = i;
            executor.submit(() -> {
                System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        executor.shutdown();
    }
}
  • 执行流程:线程池核心线程数和最大线程数都为2,任务队列容量为1。当提交第4个任务时,线程池和任务队列都已满,该任务会在调用者线程(即 main 线程)中执行。所以会看到 main 线程也参与了任务的执行。
  1. DiscardOldestPolicy
    • 策略描述:当线程池饱和时,丢弃任务队列中最老的任务(即队列头部的任务),然后尝试将新任务加入任务队列。
    • 示例代码
import java.util.concurrent.*;

public class DiscardOldestPolicyExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                2, // 最大线程数
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1), // 任务队列容量为1
                new ThreadPoolExecutor.DiscardOldestPolicy());

        for (int i = 0; i < 4; i++) {
            int taskNumber = i;
            executor.submit(() -> {
                System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        executor.shutdown();
    }
}
  • 执行流程:线程池核心线程数和最大线程数都为2,任务队列容量为1。当提交第3个任务时,任务队列已满,此时会丢弃任务队列中最早的任务(第1个加入队列的任务),然后将第3个任务加入队列。当提交第4个任务时,又会重复上述过程,丢弃队列中最早的任务(第2个加入队列的任务),将第4个任务加入队列。所以最终只有第2、3、4个任务中的两个会被执行(因为线程池只有2个线程并行执行任务)。
  1. DiscardPolicy
    • 策略描述:当线程池饱和时,直接丢弃被拒绝的任务,不做任何处理。
    • 示例代码
import java.util.concurrent.*;

public class DiscardPolicyExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                2, // 最大线程数
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1), // 任务队列容量为1
                new ThreadPoolExecutor.DiscardPolicy());

        for (int i = 0; i < 4; i++) {
            int taskNumber = i;
            executor.submit(() -> {
                System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        executor.shutdown();
    }
}
  • 执行流程:线程池核心线程数和最大线程数都为2,任务队列容量为1。当提交第3个任务时,线程池和任务队列都已满,第3个任务直接被丢弃。当提交第4个任务时,同样被丢弃。所以最终只有第1、2个任务会被执行(因为线程池只有2个线程并行执行任务,且前两个任务能成功进入队列或被线程执行)。