Java线程池 ExecutorService、ThreadPoolExecutor、ScheduledThreadPoolExecutor及Executors工厂类

本文详细介绍了Java中的线程池机制,包括ExecutorService接口、ThreadPoolExecutor和ScheduledThreadPoolExecutor的实现与使用。通过Executors工厂类创建不同类型的线程池,如cachedThreadPool、fixedThreadPool、scheduledThreadPool和singleThreadExecutor,并展示了它们的使用示例。此外,还探讨了ExecutorService的执行方法、线程数量控制、线程池关闭以及ScheduledExecutorService的定时和周期性任务执行功能。

Java中的线程池类有两个,分别是:ThreadPoolExecutor和ScheduledThreadPoolExecutor,这两个类都继承自ExecutorService。利用这两个类,可以创建各种不同的Java线程池,为了方便我们创建线程池,Java API提供了Executors工厂类来帮助我们创建各种各样的线程池。下面我们分别介绍一下这三个类。

Java线程池ExecutorService继承树:

这里写图片描述

1、ExecutorService介绍

ExecutorService是Java中对线程池定义的一个接口,它java.util.concurrent包中,在这个接口中定义了和后台任务执行相关的方法:

这里写图片描述
Java API对ExecutorService接口的实现有两个,所以这两个即是Java线程池具体实现类:

1. ThreadPoolExecutor
2. ScheduledThreadPoolExecutor

除此之外,ExecutorService还继承了Executor接口(注意区分Executor接口和Executors工厂类),这个接口只有一个execute()方法,最后我们看一下整个继承树:

2、ExecutorService的创建及使用

创建一个什么样的ExecutorService的实例(即线程池)需要根据具体应用场景而定,不过Java给我们提供了一个Executors工厂类,它可以帮助我们很方便的创建各种类型ExecutorService线程池,Executors一共可以创建下面这四类线程池:

1. newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

2.1 newCachedThreadPool

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
    final int index = i;
    try {
        Thread.sleep(index * 1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    cachedThreadPool.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println(index);
        }
    });
}
cachedThreadPool.shutdown();

2.2 newFixedThreadPool

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
    final int index = i;
    fixedThreadPool.execute(new Runnable() {

        @Override
        public void run() {
            try {
                System.out.println(index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}
fixedThreadPool.shutdown();

因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。可参考PreloadDataCache。

2.3 newScheduledThreadPool

创建一个定长线程池,支持定时及周期性任务执行。

延迟执行示例代码如下:

ScheduledExecutorService scheduledThreadPool 
                        = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
    @Override
    public void run() {
        System.out.println("delay 3 seconds");
    }
}, 3, TimeUnit.SECONDS); //表示延迟3秒执行
scheduledThreadPool.shutdown();

定期执行示例代码如下:

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("delay 1 seconds, and excute every 3 seconds");
    }
}, 1, 3, TimeUnit.SECONDS);

表示延迟1秒后每3秒执行一次。ScheduledExecutorService比Timer更安全,功能更强大。

2.4 newSingleThreadExecutor

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println(index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}
singleThreadExecutor.shutdown();

结果依次输出,相当于顺序执行各个任务。现行大多数GUI程序都是单线程的。Android中单线程可用于数据库操作,文件操作,应用批量安装,应用批量删除等不适合并发但可能IO阻塞性及影响UI线程响应的操作。

备注:Executors只是一个工厂类,它所有的方法返回的都是ThreadPoolExecutorScheduledThreadPoolExecutor这两个类的实例。

3、ExecutorService的执行

ExecutorService有如下几个执行方法:

- execute(Runnable)
- submit(Runnable)
- submit(Callable)
- invokeAny(...)
- invokeAll(...)

3.1 execute(Runnable)

这个方法接收一个Runnable实例,并且异步的执行,请看下面的实例:

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
    System.out.println("Asynchronous task");
}
});
executorService.shutdown();

这个方法存在一个问题,就是没有办法获知task的执行结果。如果我们想获得task的执行结果,我们可以传入一个Callable的实例(下面会介绍)。

3.2 submit(Runnable)

submit(Runnable)execute(Runnable)区别是前者可以返回一个Future对象,通过返回的Future对象,我们可以检查提交的任务是否执行完毕,请看下面执行的例子:

Future future = executorService.submit(new Runnable() {
public void run() {
    System.out.println("Asynchronous task");
}
});

future.get();  //returns null if the task has finished correctly.

如果任务执行完成,future.get()方法会返回一个null。注意,future.get()方法会产生阻塞。

3.3 submit(Callable)

submit(Callable)submit(Runnable) 类似,也会返回一个Future对象,但是除此之外,submit(Callable)接收的是一个Callable的实现,Callable接口中的call()方法有一个返回值,可以返回任务的执行结果,而Runnable接口中的run()方法是void的,没有返回值。请看下面实例:

Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
    System.out.println("Asynchronous Callable");
    return "Callable Result";
}
});

System.out.println("future.get() = " + future.get());

如果任务执行完成,future.get()方法会返回Callable任务的执行结果。注意,future.get()方法会产生阻塞。

3.4 invokeAny(…)

invokeAny(...)方法接收的是一个Callable的集合,执行这个方法不会返回Future,但是会返回所有Callable任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果,反正是其中的某一个。请看下面实例:

ExecutorService executorService = Executors.newSingleThreadExecutor();

Set<Callable<String>> callables = new HashSet<Callable<String>>();

callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 2";
}
});
callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 3";
}
});

String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();

大家可以尝试执行上面代码,每次执行都会返回一个结果,并且返回的结果是变化的,可能会返回“Task2”也可是“Task1”或者其它。

3.5 invokeAll(…)

invokeAll(...)与 invokeAny(...)类似也是接收一个Callable集合,但是前者执行之后会返回一个Future的List,其中对应着每个Callable任务执行后的Future对象。情况下面这个实例:

ExecutorService executorService = Executors.newSingleThreadExecutor();

Set<Callable<String>> callables = new HashSet<Callable<String>>();

callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 1";
}
});
callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
    return "Task 3";
}
});

List<Future<String>> futures = executorService.invokeAll(callables);

for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}

executorService.shutdown();

4、ExecutorService的关闭

当我们使用完成ExecutorService之后应该关闭它,否则它里面的线程会一直处于运行状态。

举个例子,如果的应用程序是通过main()方法启动的,在这个main()退出之后,如果应用程序中的ExecutorService没有关闭,这个应用将一直运行。之所以会出现这种情况,是因为ExecutorService中运行的线程会阻止JVM关闭。

如果要关闭ExecutorService中执行的线程,我们可以调用ExecutorService.shutdown()方法。在调用shutdown()方法之后,ExecutorService不会立即关闭,但是它不再接收新的任务,直到当前所有线程执行完成才会关闭,所有在shutdown()执行之前提交的任务都会被执行。

如果我们想立即关闭ExecutorService,我们可以调用ExecutorService.shutdownNow()方法。这个动作将跳过所有正在执行的任务和被提交还没有执行的任务。但是它并不对正在执行的任务做任何保证,有可能它们都会停止,也有可能执行完成。

5、ThreadPoolExecutor

ThreadPoolExecutor是ExecutorService的一个实现类,也是java中最常用的线程池类。ThreadPoolExecutor内部维持了一个线程池,可以执行给定的任务,下面是关于它的具体使用方法。

Java 线程池工作过程
  1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
  2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断(见下方5.2中数量控制)
  3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。
  4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运
    行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它
    最终会收缩到 corePoolSize 的大小。

5.1 ThreadPoolExecutor构造方法及其作用

ThreadPoolExecutor源码中的构造方法:

这里写图片描述

- corePoolSize:线程池维护线程的最少数量
- maximumPoolSize:线程池维护线程的最大数量
- keepAliveTime: 线程池维护线程所允许的空闲时间
- unit: 线程池维护线程所允许的空闲时间的单位
- workQueue: 线程池所使用的缓冲队列
- handler: 线程池对拒绝任务的处理策略

5.2 线程数量控制

ThreadPoolExecutor线程池中的线程数量是可变的,其变化范围取决于下面两个变量:

1. corePoolSize:线程池维护线程的最少数量
2. maximumPoolSize:线程池维护线程的最大数量

具体线程的分配方式是,当一个任务被添加到线程池:

  • 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
  • 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
  • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
  • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
  • 当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。

这样,线程池可以动态的调整池中的线程数。除了corePoolSizemaximumPoolSize两个变量外,ThreadPoolExecutor构造方法还有几个参数:

  • keepAliveTime: 线程池维护线程所允许的空闲时间
  • unit: 线程池维护线程所允许的空闲时间的单位
  • workQueue: 线程池所使用的缓冲队列
  • handler: 线程池对拒绝任务的处理策略

5.2.1 unit

unit 可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:

- NANOSECONDS
- MICROSECONDS
- MILLISECONDS
- SECONDS

5.2.2 workQueue

workQueue是一个BlockingQueue,默认是LinkedBlockingQueue<Runnable>

5.2.3 handler

handler 是线程池拒绝处理任务的方式,主要有四种类型:

  1. ThreadPoolExecutor.AbortPolicy()(系统默认):抛出java.util.concurrent.RejectedExecutionException异常
  2. ThreadPoolExecutor.CallerRunsPolicy():当抛出RejectedExecutionException异常时,会调用rejectedExecution方法,只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。显然这样做不会真的丢弃任务,但是,任务提交线程的性能极有可能会急剧下降。
  3. ThreadPoolExecutor.DiscardOldestPolicy():丢弃最老的一个请求,也就是即将被执行的一个任务,并尝试再次提交当前任务。
  4. ThreadPoolExecutor.DiscardPolicy():该策略默默地丢弃无法处理的任务,不予任何处理。如果允许任务丢失,这是最好的一种方案。
以上内置拒绝策略均实现了 RejectedExecutionHandler 接口,若以上策略仍无法满足实际 需要,完全可以自己扩展 RejectedExecutionHandler 接口。

5.2.4 创建一个ThreadPoolExecutor

int  corePoolSize  =    5;
int  maxPoolSize   =   10;
long keepAliveTime = 5000;

ExecutorService threadPoolExecutor =
    new ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            keepAliveTime,
            TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()
            );

6、ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor是ExecutorService的另一个实现类,从上面Java线程池ExecutorService继承树这幅图可以看出,ScheduledThreadPoolExecutor直接继承自ScheduledExecutorService,ScheduledThreadPoolExecutor 类的功能也主要体现在ScheduledExecutorService 接口上,而所以在介绍ScheduledThreadPoolExecutor之前先介绍一下ScheduledExecutorService接口。

6.1 ScheduledExecutorService接口介绍

java.util.concurrent.ScheduledExecutorService接口继承了ExecutorService,它的最主要的功能就是可以对其中的任务进行调度,比如延迟执行、定时执行等等。

ScheduledExecutorService接口定义:

public interface ScheduledExecutorService extends ExecutorService {

    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);

    public ScheduledFuture<?> schedule(Callable task, long delay, TimeUnit timeunit);

    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay, long period, TimeUnit unit);

    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay, long delay,TimeUnit unit);

}

6.1.1 schedule (Runnable task, long delay, TimeUnit timeunit)
这个方法的意思是在指定延迟之后运行task。这个方法有个问题,就是没有办法获知task的执行结果。如果我们想获得task的执行结果,我们可以传入一个Callable的实例(后面会介绍)。
 

ScheduledExecutorService scheduledExecutorService =
    Executors.newScheduledThreadPool(5);

ScheduledFuture scheduledFuture =
scheduledExecutorService.schedule(new Callable() {
    public Object call() throws Exception {
        System.out.println("Executed!");
        return "Called!";
    }
},5,TimeUnit.SECONDS);
System.out.println("result = " + scheduledFuture.get());
scheduledExecutorService.shutdown();

6.1.2 schedule (Callable task, long delay, TimeUnit timeunit)

这个方法与schedule (Runnable task)类似,也是在指定延迟之后运行task,不过它接收的是一个Callable实例,此方法会返回一个ScheduleFuture对象,通过ScheduleFuture我们可以取消一个未执行的task,也可以获得这个task的执行结果。

ScheduledExecutorService scheduledExecutorService =
    Executors.newScheduledThreadPool(5);

ScheduledFuture scheduledFuture =
scheduledExecutorService.schedule(new Callable() {
    public Object call() throws Exception {
        System.out.println("Executed!");
        return "Called!";
    }
},5,TimeUnit.SECONDS);

System.out.println("result = " + scheduledFuture.get());
scheduledExecutorService.shutdown();

6.1.3 scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
这个方法的作用是周期性的调度task执行。task第一次执行的延迟根据initialDelay参数确定,以后每一次执行都间隔period时长。

如果task的执行时间大于定义的period,那么下一个线程将在当前线程完成之后再执行。整个调度保证不会出现一个以上任务同时执行。

6.1.4 scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)
scheduleWithFixedDelay的参数和scheduleAtFixedRate参数完全一致,它们的不同之处在于对period调度周期的解释。

在scheduleAtFixedRate中,period指的两个任务开始执行的时间间隔,也就是当前任务的开始执行时间和下个任务的开始执行时间之间的间隔。

而在scheduleWithFixedDelay中,period指的当前任务的结束执行时间到下个任务的开始执行时间。

6.1.5 ScheduledExecutorService的关闭
和ExecutorService类似, 我们在使用完ScheduledExecutorService时需要关闭它。如果不关闭的话,JVM会一直运行直,即使所有线程已经关闭了。

关闭ScheduledExecutorService可以使用其继承自ExecutorService接口的shutdown()和shutdownNow()方法。

6.2 ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,构造参数很简单,只有3个:

1. int corePoolSize:线程池维护线程的最少数量
2. ThreadFactory threadFactory:线程工程类,线程池用它来制造线程
3. RejectedExecutionHandler handler:线程池对拒绝任务的处理策略

具体使用方法请参考上方ThreadPoolExecutor或者使用Executors。

7、Executors

创建一个什么样的ExecutorService的实例(即线程池)需要我们的具体应用场景而定,不过Java给我们提供了一个Executors工厂类,它可以帮助我们很方便的创建各种类型ExecutorService线程池,Executors一共可以创建下面这四类线程池:

  • newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

备注:Executors只是一个工厂类,它所有的方法返回的都是ThreadPoolExecutor、ScheduledThreadPoolExecutor这两个类的实例。

<think>我们正在讨论Java线程池ExecutorService,用户希望了解其使用、原理及最佳实践。根据之前的对话历史和提供的参考资料,我们可以系统地组织回答。 参考资料摘要: [^1]:ThreadPoolExecutor线程池的核心实现Executors工厂提供便捷创建方法。 [^2]:ThreadPoolExecutorScheduledThreadPoolExecutor都实现了Executor和ExecutorService接口。 [^3]:线程池中的线程用Worker对象封装,Worker是ThreadPoolExecutor的内部,持有线程池引用。 [^4]:介绍了不同型的线程池(Fixed, Cached, SingleThread, Scheduled, WorkStealing)及其使用场景。 回答结构: 1. ExecutorService概述:介绍其在Java并发包中的地位和作用。 2. 使用指南:如何创建(通过Executors工厂或直接构造ThreadPoolExecutor)、提交任务、关闭线程池。 3. 核心原理:重点解释ThreadPoolExecutor的工作原理(任务调度、线程复用、队列管理、拒绝策略等)。 4. 最佳实践:参数配置、线程池选择、异常处理、监控等。 5. 常见问题与解决方案:如任务堆积、死锁、资源泄露等。 注意引用标注:在关键结论或数据后添加引用标识。 数学表达式:如线程池性能模型中的公式需要用$...$或$$...$$表示。 最后生成相关问题。 </think>### Java线程池`ExecutorService`的使用、原理及最佳实践 `ExecutorService`是Java并发包(`java.util.concurrent`)的核心接口,用于管理线程池的生命周期和任务执行。以下从使用、原理和实践三个维度展开: --- #### 一、使用指南 1. **创建线程池** 通过`Executors`工厂或直接构造`ThreadPoolExecutor`实现: ```java // 工厂方法(推荐简单场景) ExecutorService fixedPool = Executors.newFixedThreadPool(10); // 固定大小线程池 [^4] ExecutorService cachedPool = Executors.newCachedThreadPool(); // 弹性线程池(需防OOM)[^4] ExecutorService singlePool = Executors.newSingleThreadExecutor(); // 单线程顺序执行 [^4] // 手动配置(推荐生产环境) ExecutorService customPool = new ThreadPoolExecutor( corePoolSize, // 核心线程数(常驻) maxPoolSize, // 最大线程数(队列满时扩容) keepAliveTime, // 非核心线程空闲存活时间 TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), // 任务队列 new CustomRejectedPolicy() // 自定义拒绝策略 ); ``` 2. **提交任务** - `execute(Runnable task)`: 提交无返回值的任务 - `submit(Callable<T> task)`: 提交有返回值的任务,返回`Future<T>`对象 ```java Future<Integer> future = customPool.submit(() -> { // 计算逻辑 return 42; }); Integer result = future.get(); // 阻塞获取结果 ``` 3. **关闭线程池** ```java customPool.shutdown(); // 优雅关闭:停止接收新任务,处理完队列任务 customPool.shutdownNow(); // 强制关闭:中断所有线程(返回未处理任务列表) ``` --- #### 二、核心原理 1. **任务调度流程** - 提交任务时,优先创建核心线程执行(若核心线程数未满) - 核心线程满载后,任务进入阻塞队列 - 队列满载后,创建非核心线程(不超过`maxPoolSize`) - 线程和队列均满载时,触发拒绝策略 [^1][^2] 2. **线程复用机制** 线程池通过`Worker`内部封装线程(继承`AQS`锁)[^3]: ```java private final class Worker extends AbstractQueuedSynchronizer implements Runnable { final Thread thread; // 实际工作线程 Runnable firstTask; // 初始任务 // 线程执行循环:从队列获取任务并执行 } ``` - 线程启动后循环执行`getTask()`从队列获取任务 - 空闲线程超时(`keepAliveTime`)后被回收 3. **生命周期状态** 通过原子变量`ctl`(32位)维护两种状态: - **高3位**:线程池状态(`RUNNING`, `SHUTDOWN`, `STOP`, `TIDYING`, `TERMINATED`) - **低29位**:有效线程数 状态转换关系: $$ \text{RUNNING} \xrightarrow{\text{shutdown()}} \text{SHUTDOWN} \xrightarrow{\text{队列空}} \text{TIDYING} \xrightarrow{\text{terminated()}} \text{TERMINATED} $$ [^2][^4] --- #### 三、最佳实践 1. **参数配置优化** - **核心公式**:最佳线程数 $N_{\text{threads}} = N_{\text{CPU}} \times U_{\text{CPU}} \times (1 + \frac{W}{C})$ - $N_{\text{CPU}}$:CPU核心数(`Runtime.getRuntime().availableProcessors()`) - $U_{\text{CPU}}$:目标CPU利用率(通常取0.8) - $W/C$:等待时间与计算时间的比值 - **队列容量**:根据业务峰谷值设置,避免`OOM`(如`ArrayBlockingQueue`有界队列)[^1] 2. **拒绝策略选择** | 策略 | 行为 | 适用场景 | |------|------|----------| | `AbortPolicy`(默认) | 抛出`RejectedExecutionException` | 需快速失败场景 | | `CallerRunsPolicy` | 由提交任务的线程执行 | 保证任务不丢失 | | `DiscardPolicy` | 静默丢弃任务 | 容忍数据丢失 | | `DiscardOldestPolicy` | 丢弃队列最旧任务并重试 | 时效性优先 | 3. **监控与调优** - 通过`ThreadPoolExecutor`方法监控: ```java pool.getActiveCount(); // 活动线程数 pool.getQueue().size(); // 队列积压量 ``` - **问题诊断**: - 线程饥饿:增大核心线程数或改用`SynchronousQueue` - CPU过高:降低线程数或优化任务逻辑 - OOM风险:使用有界队列并设置合理拒绝策略 [^4] 4. **场景化选型** | 线程池型 | 特点 | 适用场景 | |------------|------|----------| | `FixedThreadPool` | 固定线程数 | 负载稳定的服务(如Web后端) | | `CachedThreadPool` | 线程自动回收 | 短时异步任务(需防OOM) | | `ScheduledThreadPool` | 支持定时任务 | 心跳检测、定时报表 [^4] | | `WorkStealingPool` | 工作窃取负载均衡 | CPU密集型并行计算 [^4] | --- #### 四、常见问题解决方案 1. **任务堆积导致OOM** **方案**:使用有界队列 + `CallerRunsPolicy`拒绝策略,限制提交速率。 2. **线程泄漏** **方案**:确保任务正确处理异常(避免线程因异常终止),或使用`ThreadFactory`定制线程的`UncaughtExceptionHandler`。 3. **死锁** **方案**:避免任务间循环依赖;使用`newWorkStealingPool()`利用工作窃取算法打破僵局 [^4]。 4. **资源竞争** **方案**:对共享资源使用`ConcurrentHashMap`等并发容器;控制线程数不超过$2 \times N_{\text{CPU}}$。 > **关键原则**:根据业务场景(I/O密集型或CPU密集型)动态调整参数,并通过压测验证[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值