Java多线程之ThreadPoolTaskExecutor用法

一、简介

ThreadPoolTaskExecutor线程是Spring的线程池,其底层是依据JDK线程池ThreadPoolExecutor来实现的。

 

二、参数介绍

corePoolSize:线程池维护线程最小的数量,默认为1
maxPoolSize:线程池维护线程最大数量,默认为Integer.MAX_VALUE
keepAliveSeconds:(maxPoolSize-corePoolSize)部分线程空闲最大存活时间,默认存活时间是60s
queueCapacity:阻塞任务队列的大小,默认为Integer.MAX_VALUE,默认使用LinkedBlockingQueue
allowCoreThreadTimeOut:设置为true的话,keepAliveSeconds参数设置的有效时间对corePoolSize线程也有效,默认是flase
threadFactory::用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。使用开源框架guava提供的ThreadFactoryBuilder可以快速给线程池里的线程设置有意义的名字
rejectedExecutionHandler:拒绝策略,当队列workQueue和线程池maxPoolSize都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。

 

三、拒绝策略

拒绝策略有以下四种,默认情况下是AbortPolicy,也可根据实际业务需求类实现RejectedExecutionHandler接口实现自己的处理策略
1.AbortPolicy:丢弃任务,并且抛出RejectedExecutionException异常;
2.DiscardPolicy:丢弃任务,不处理,不抛出异常;
3.CallerRunsPolicy:直接在execute方法的调用线程中运行被拒绝的任务;
4.DiscardOldestPolicy:丢弃队列中最前面的任务,然后重新尝试执行任务。

 

四、处理流程

1.查看核心线程池是否已满,不满就创建一条线程执行任务,否则执行第二步。
2.查看任务队列是否已满,不满就将任务存储在任务队列中,否则执行第三步。
3.查看线程池是否已满,即就是是否达到最大线程池数,不满就创建一条线程执行任务,否则就按照策略处理无法执行的任务。

 

四、代码示例

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
    /**
     * ThreadPoolTaskExecutor用法:
     * corePoolSize:线程池维护线程最小的数量,默认为1
     * maxPoolSize:线程池维护线程最大数量,默认为Integer.MAX_VALUE
     * keepAliveSeconds:(maxPoolSize-corePoolSize)部分线程空闲最大存活时间,默认存活时间是60s
     * queueCapacity:阻塞任务队列的大小,默认为Integer.MAX_VALUE,默认使用LinkedBlockingQueue
     * allowCoreThreadTimeOut:设置为true的话,keepAliveSeconds参数设置的有效时间对corePoolSize线程也有效,默认是flase
     * threadFactory::用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。使用开源框架guava提供的ThreadFactoryBuilder可以快速给线程池里的线程设置有意义的名字
     * rejectedExecutionHandler:拒绝策略,当队列workQueue和线程池maxPoolSize都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常,有以下四种策略,当然也可以根据实际业务需求类实现RejectedExecutionHandler接口实现自己的处理策略
     * 1.AbortPolicy:丢弃任务,并且抛出RejectedExecutionException异常
     * 2.DiscardPolicy:丢弃任务,不处理,不抛出异常
     * 3.CallerRunsPolicy:直接在execute方法的调用线程中运行被拒绝的任务
     * 4.DiscardOldestPolicy:丢弃队列中最前面的任务,然后重新尝试执行任务
     */
    @Test()
    public void _03_test() throws Exception {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3); //核心池大小
        executor.setMaxPoolSize(10); //最大线程数
        executor.setQueueCapacity(10); //队列程度
        executor.setKeepAliveSeconds(60); //线程空闲时间
        executor.setThreadNamePrefix("子线程-");//线程前缀名称
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); //配置拒绝策略
        executor.initialize(); //初始化

        Runnable task = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " 工作开始!");
                    Thread.sleep((long) (Math.random() * 2000));
//                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName() + " 工作结束!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        for (int i = 0; i < 5; i++) {
            executor.execute(task);
        }
        int n = Runtime.getRuntime().availableProcessors();//获取到服务器的cpu内核
        log.info("服务器的cpu内核:{}", n);

        Thread.sleep(5000);
        System.out.println("主线程工作结束!");
        executor.shutdown();
    }

 运行结果:

03-02 14:39:00 Initializing ExecutorService 
子线程-1 工作开始!
子线程-3 工作开始!
子线程-2 工作开始!
03-02 14:39:00 服务器的cpu内核:8 
子线程-3 工作结束!
子线程-3 工作开始!
子线程-2 工作结束!
子线程-2 工作开始!
子线程-2 工作结束!
子线程-1 工作结束!
子线程-3 工作结束!
主线程工作结束!
03-02 14:39:05 Shutting down ExecutorService 

 

五、多线程同步工具用法

/**
     * 多线程同步工具用法(单独方法)
     * ThreadPoolTaskExecutor和CountDownLatch结合用法
     */
    @Test
    public void _05_test() throws Exception {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3); //核心池大小
        executor.setMaxPoolSize(10); //最大线程数
        executor.setQueueCapacity(10); //队列程度
        executor.setThreadNamePrefix("子线程-");//线程前缀名称
        executor.initialize(); //初始化

        int count = 5; // 任务数量
        CountDownLatch countDownLatch = new CountDownLatch(count); // 同步工具
        for (int i = 0; i < count; i++) {
            executor.execute(() -> task(countDownLatch));
        }
        System.out.println("等待子线程完成...");
        countDownLatch.await();
        System.out.println("主线程工作结束!");
        executor.shutdown();
    }

    private void task(CountDownLatch countDownLatch) {
        try {
            System.out.println(Thread.currentThread().getName() + " 工作开始!");
            Thread.sleep((long) (Math.random() * 2000));
            System.out.println(Thread.currentThread().getName() + " 工作结束!");
            countDownLatch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

运行结果:

03-02 14:59:41 Initializing ExecutorService 
子线程-1 工作开始!
子线程-2 工作开始!
子线程-3 工作开始!
等待子线程完成
子线程-2 工作结束!
子线程-2 工作开始!
子线程-3 工作结束!
子线程-3 工作开始!
子线程-2 工作结束!
子线程-3 工作结束!
子线程-1 工作结束!
主线程工作结束!
03-02 14:59:42 Shutting down ExecutorService 

 

丢弃队列中最前面的任务,然后重新尝试执行任务
posted @ 2021-03-02 14:33  星瑞  阅读(14023)  评论(0编辑  收藏  举报