MST

星途 面试题库

面试题:Java共享线程池场景下,如何优化线程池以避免饥饿问题

在Java中,当多个任务共享同一个线程池时,可能会出现饥饿问题。请详细阐述你会如何通过调整线程池的策略(如拒绝策略、任务优先级处理等)来避免该问题,并结合具体的代码示例说明。
13.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. 饥饿问题分析

线程饥饿指的是某些任务因为得不到足够的资源(这里是线程资源)而无法执行。在共享线程池场景下,高优先级任务持续不断到来,会导致低优先级任务长时间得不到执行机会。

2. 调整线程池策略避免饥饿问题

  • 拒绝策略:通过合理设置拒绝策略,可以在任务无法入队时,采取合适的处理方式,避免任务堆积导致饥饿。例如使用CallerRunsPolicy拒绝策略,当线程池饱和且任务队列已满时,将任务回退给调用者线程执行,这样可以保证新任务不会无限堆积,一定程度上缓解饥饿。
  • 任务优先级处理:可以在任务类中实现优先级接口,在提交任务时,线程池按照优先级调度任务。例如,使用PriorityBlockingQueue作为任务队列,它会按照任务的优先级排序,优先执行高优先级任务,但为了避免低优先级任务饿死,需要配合一定的调度算法。

3. 代码示例

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

class PrioritizedTask implements Callable<String>, Comparable<PrioritizedTask> {
    private final int priority;
    private final String taskName;

    public PrioritizedTask(int priority, String taskName) {
        this.priority = priority;
        this.taskName = taskName;
    }

    @Override
    public String call() throws Exception {
        // 模拟任务执行
        Thread.sleep(1000);
        return "Task " + taskName + " with priority " + priority + " executed.";
    }

    @Override
    public int compareTo(PrioritizedTask other) {
        return Integer.compare(this.priority, other.priority);
    }
}

public class ThreadPoolStarvationExample {
    public static void main(String[] args) {
        int corePoolSize = 2;
        int maximumPoolSize = 4;
        long keepAliveTime = 10L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new PriorityBlockingQueue<>();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
        ExecutorService executorService = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                handler);

        PrioritizedTask task1 = new PrioritizedTask(1, "Task1");
        PrioritizedTask task2 = new PrioritizedTask(2, "Task2");
        PrioritizedTask task3 = new PrioritizedTask(3, "Task3");

        try {
            System.out.println(executorService.submit(task1).get());
            System.out.println(executorService.submit(task2).get());
            System.out.println(executorService.submit(task3).get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

在上述代码中:

  • PrioritizedTask类实现了CallableComparable接口,通过compareTo方法定义了任务优先级。
  • 使用PriorityBlockingQueue作为线程池的任务队列,保证高优先级任务优先执行。
  • 采用CallerRunsPolicy拒绝策略,当线程池和任务队列都满时,任务由调用者线程执行,避免任务无限堆积。