线程池:ThreadPoolExector

本文详细介绍了Java中的线程池实现类ThreadPoolExecutor的继承关系及其重要接口ExecutorService的功能。探讨了execute与submit的区别,并讲解了线程池的七大参数和四种拒绝策略,包括AbortPolicy、DiscardPolicy、DiscardOldestPolicy和CallerRunsPolicy,以及它们在任务无法执行时的不同处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ThreadPoolExecutor继承关系

Java中的线程池有两个核心的类:ThreadPoolExector 和 ScheduledThreadPoolExecutor,以ThreadPoolExecutor为例,下图为ThreadPoolExecutor的继承关系。
在这里插入图片描述

ThreadPoolExecutor实现的顶层接口是Executor,顶层接口Executor提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程,如何调度线程来执行任务,用户只需提供Runnable对象,将任务的运行逻辑提交到执行器(Executor)中,由Executor框架完成线程的调配和任务的执行部分。
ExecutorService接口增加了一些能力:(1)扩充执行任务的能力,补充可以为一个或一批异步任务生成Future的方法;(2)提供了管控线程池的方法,比如停止线程池的运行。

public interface ExecutorService extends Executor {
	void shutdown();
	<T> Future<T> submit(Callable<T> task);
	<T> Future<T> submit(Runnable task, T result);
	<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
}

Ps:execute 和 submit 区别

submit 有返回值,execute 没有返回值。 所以说可以根据任务有无返回值选择对应的方法。

   FutureTask<Integer> submit2 = (FutureTask<Integer>) pool.submit(new Callable<Integer>() {
                public Integer call() throws Exception {
                    return 1;
                }
            });
   System.out.println(submit2.get());

submit 方便异常的处理。 如果任务可能会抛出异常,而且希望外面的调用者能够感知这些异常,那么就需要

    Future future = pool.submit(new RunnableTest("Task2"));
        
        try {
            if(future.get()==null){//如果Future's get返回null,任务完成
                System.out.println("任务完成");
            }
        } catch (InterruptedException e) {
        } catch (ExecutionException e) {
            //否则我们可以看看任务失败的原因是什么
            System.out.println(e.getCause().getMessage());
        }

AbstractExecutorService则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法即可。最下层的实现类ThreadPoolExecutor实现最复杂的运行部分,ThreadPoolExecutor将会一方面维护自身的生命周期,另一方面同时管理线程和任务,使两者良好的结合从而执行并行任务。

线程池执行流程

线程池7大参数


int corePoolSize, // 核心线程池大小                         
int maximumPoolSize, // 线程池最大容量                      
long keepAliveTime, // 超时了没有人调用就会释放                          
TimeUnit unit, // 超时单位                         
BlockingQueue<Runnable> workQueue, // 阻塞队列                          
ThreadFactory threadFactory, // 线程工厂:创建线程的,一般不用动                          
RejectedExecutionHandler handle // 拒绝策略) 

线程池4种拒绝策略

第一种拒绝策略是 AbortPolicy,默认的拒绝策略,拒绝策略在拒绝任务时,会直接抛出一个类型为 RejectedExecutionException 的 RuntimeException,让你感知到任务被拒绝了,于是你便可以根据业务逻辑选择重试或者放弃提交等策略。

第二种拒绝策略是 DiscardPolicy,这种拒绝策略正如它的名字所描述的一样,当新任务被提交后直接被丢弃掉,也不会给你任何的通知,相对而言存在一定的风险,因为我们提交的时候根本不知道这个任务会被丢弃,可能造成数据丢失。

第三种拒绝策略是 DiscardOldestPolicy,如果线程池没被关闭且没有能力执行,则会丢弃任务队列中的头结点,通常是存活时间最长的任务,这种策略与第二种不同之处在于它丢弃的不是最新提交的,而是队列中存活时间最长的,这样就可以腾出空间给新提交的任务,但同理它也存在一定的数据丢失风险。

第四种拒绝策略是 CallerRunsPolicy,相对而言它就比较完善了,当有新任务提交后,如果线程池没被关闭且没有能力执行,则把这个任务交于提交任务的线程执行,也就是谁提交任务,谁就负责执行任务。

在这里插入图片描述

首先检测线程池运行状态,如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。

  • 当workerCount < corePoolSize,则创建并启动一个线程来执行新提交的任务。

  • 当workerCount >= corePoolSize,且线程池内的阻塞队列未满,则将任务添加到该阻塞队列中。

  • 当workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满,则创建并启动一个线程来执行新提交的任务。

  • 当 workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。

举例说明

ExecutorService pool = new ThreadPoolExecutor(2,
        3, 1,TimeUnit.MICROSECONDS,
        new ArrayBlockingQueue(4),
        Executors.defaultThreadFactory());
for(int i = 0; i < 100; i++){
    pool.execute(new Runnable() {
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    });

在这里插入图片描述

public class Test {
    private static ExecutorService pool;
    public static void main( String[] args )
    {
        //自定义线程工厂
        pool = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5),
                new ThreadFactory() {
                    public Thread newThread(Runnable r) {
                        System.out.println("线程"+r.hashCode()+"创建");
                        //线程命名
                        Thread th = new Thread(r,"threadPool"+r.hashCode());
                        return th;
                    }
                }, new ThreadPoolExecutor.CallerRunsPolicy());

        for(int i=0;i<10;i++) {
            pool.execute(new ThreadTask());
        }
    }
}

class ThreadTask implements Runnable{
    public void run() {
        //输出执行线程的名称
        System.out.println("ThreadName:"+Thread.currentThread().getName());
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值