Spring使用ThreadPoolTaskExecutor自定义线程池及异步调用方式

目录
  • 一、ThreadPoolTaskExecutor
    • 1、将线程池用到的参数定义到配置文件中
    • 2、Executors的工厂配置
      • 2.1、配置详情
      • 2.2、注解说明
      • 2.3、线程池配置说明
      • 2.4、线程池配置个人理解
  • 二、异步调用线程
  • 三、多线程使用场景
    • 1、定时任务@Scheduled
    • 2、程序一启动就异步执行多线程
    • 3、定义一个http接口
    • 4、测试类
  • 四、总结

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。

一、ThreadPoolTaskExecutor

本文采用 Executors 的工厂方法进行配置。

1、将线程池用到的参数定义到配置文件中

在项目的 resources 目录下创建 executor.properties 文件,并添加如下配置:

# 异步线程配置
# 核心线程数
async.executor.thread.core_pool_size=5
# 最大线程数
async.executor.thread.max_pool_size=8
# 任务队列大小
async.executor.thread.queue_capacity=2
# 线程池中线程的名称前缀
async.executor.thread.name.prefix=async-service-
# 缓冲队列中线程的空闲时间
async.executor.thread.keep_alive_seconds=100

2、Executors 的工厂配置

2.1、配置详情

@Configuration
// @PropertySource是找的target目录下classes目录下的文件,resources目录下的文件编译后会生成在classes目录
@PropertySource(value = {"classpath:executor.properties"}, ignoreResourceNotFound=false, encoding="UTF-8")
@Slf4j
public class ExecutorConfig {
    @Value("${async.executor.thread.core_pool_size}")
    private int corePoolSize;
    @Value("${async.executor.thread.max_pool_size}")
    private int maxPoolSize;
    @Value("${async.executor.thread.queue_capacity}")
    private int queueCapacity;
    @Value("${async.executor.thread.name.prefix}")
    private String namePrefix;
    @Value("${async.executor.thread.keep_alive_seconds}")
    private int keepAliveSeconds;
    @Bean(name = "asyncTaskExecutor")
    public ThreadPoolTaskExecutor taskExecutor() {
        log.info("启动");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(corePoolSize);
        // 最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        // 任务队列大小
        executor.setQueueCapacity(queueCapacity);
        // 线程前缀名
        executor.setThreadNamePrefix(namePrefix);
        // 线程的空闲时间
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 线程初始化
        executor.initialize();
        return executor;
    }
}

2.2、注解说明

  • @Configuration:Spring 容器在启动时,会加载带有 @Configuration 注解的类,对其中带有 @Bean 注解的方法进行处理。
  • @Bean:是一个方法级别上的注解,主要用在 @Configuration 注解的类里,也可以用在 @Component 注解的类里。添加的 bean 的 id 为方法名。
  • @PropertySource:加载指定的配置文件。value 值为要加载的配置文件,ignoreResourceNotFound 意思是如果加载的文件找不到,程序是否忽略它。默认为 false 。如果为 true ,则代表加载的配置文件不存在,程序不报错。在实际项目开发中,最好设置为 false 。如果 application.properties 文件中的属性与自定义配置文件中的属性重复,则自定义配置文件中的属性值被覆盖,加载的是 application.properties 文件中的配置属性。
  • @Slf4j:lombok 的日志输出工具,加上此注解后,可直接调用 log 输出各个级别的日志。
  • @Value:调用配置文件中的属性并给属性赋予值。

2.3、线程池配置说明

  • 核心线程数:线程池创建时候初始化的线程数。当线程数超过核心线程数,则超过的线程则进入任务队列。
  • 最大线程数:只有在任务队列满了之后才会申请超过核心线程数的线程。不能小于核心线程数。
  • 任务队列:线程数大于核心线程数的部分进入任务队列。如果任务队列足够大,超出核心线程数的线程不会被创建,它会等待核心线程执行完它们自己的任务后再执行任务队列的任务,而不会再额外地创建线程。举例:如果有20个任务要执行,核心线程数:10,最大线程数:20,任务队列大小:2。则系统会创建18个线程。这18个线程有执行完任务的,再执行任务队列中的任务。
  • 线程的空闲时间:当 线程池中的线程数量 大于 核心线程数 时,如果某线程空闲时间超过 keepAliveTime ,线程将被终止。这样,线程池可以动态的调整池中的线程数。
  • 拒绝策略:如果(总任务数 - 核心线程数 - 任务队列数)-(最大线程数 - 核心线程数)> 0 的话,则会出现线程拒绝。举例:( 12 - 5 - 2 ) - ( 8 - 5 ) > 0,会出现线程拒绝。线程拒绝又分为 4 种策略,分别为:
  • CallerRunsPolicy():交由调用方线程运行,比如 main 线程。
  • AbortPolicy():直接抛出异常。
  • DiscardPolicy():直接丢弃。
  • DiscardOldestPolicy():丢弃队列中最老的任务。

2.4、线程池配置个人理解

  • 当一个任务被提交到线程池时,首先查看线程池的核心线程是否都在执行任务。如果没有,则选择一条线程执行任务。
  • 如果都在执行任务,查看任务队列是否已满。如果不满,则将任务存储在任务队列中。核心线程执行完自己的任务后,会再处理任务队列中的任务。
  • 如果任务队列已满,查看线程池(最大线程数控制)是否已满。如果不满,则创建一条线程去执行任务。如果满了,就按照策略处理无法执行的任务。

二、异步调用线程

通常 ThreadPoolTaskExecutor 是和 @Async 一起使用。在一个方法上添加 @Async 注解,表明是异步调用方法函数。

@Async 后面加上线程池的方法名或 bean 名称,表明异步线程会加载线程池的配置。

@Component
@Slf4j
public class ThreadTest {
    /**
     * 每10秒循环一次,一个线程共循环10次。
     */
    @Async("asyncTaskExecutor")
    public void ceshi3() {
        for (int i = 0; i <= 10; i  ) {
            log.info("ceshi3: "   i);
            try {
                Thread.sleep(2000 * 5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

备注:一定要在启动类上添加 @EnableAsync 注解,这样 @Async 注解才会生效。

三、多线程使用场景

1、定时任务 @Scheduled

// 在启动类上添加 @EnableScheduling 注解
@SpringBootApplication
@EnableScheduling
public class SpringBootStudyApplication {
   public static void main(String[] args) {
      SpringApplication.run(SpringBootStudyApplication.class, args);
   }
}
// @Component 注解将定时任务类纳入 spring bean 管理。
@Component
public class listennerTest3 {
    @Autowired
    private ThreadTest t;
    
    // 每1分钟执行一次ceshi3()方法
    @Scheduled(cron = "0 0/1 * * * ?")
    public void run() {
        t.ceshi3();
    }
}

ceshi3() 方法调用线程池配置,且异步执行。

@Component
@Slf4j
public class ThreadTest {
    /**
     * 每10秒循环一次,一个线程共循环10次。
     */
    @Async("asyncTaskExecutor")
    public void ceshi3() {
        for (int i = 0; i <= 10; i  ) {
            log.info("ceshi3: "   i);
            try {
                Thread.sleep(2000 * 5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2、程序一启动就异步执行多线程

通过继承 CommandLineRunner 类实现。

@Component
public class ListennerTest implements CommandLineRunner {
    @Autowired
    private ThreadTest t;
    @Override
    public void run(String... args) {
        for (int i = 1; i <= 10; i  ) {
            t.ceshi();
        }
    }
}
@Component
@Slf4j
public class ThreadTest {
    @Async("asyncTaskExecutor")
    public void ceshi() {
        log.info("ceshi");
    }
}    

3、定义一个 http 接口

还可以通过接口的形式来异步调用多线程:

@RestController
@RequestMapping("thread")
public class ListennerTest2 {
    @Autowired
    private ThreadTest t;
    @GetMapping("ceshi2")
    public void run() {
        for (int i = 1; i < 10; i  ) {
            t.ceshi2();
        }
    }
}
@Component
@Slf4j
public class ThreadTest {
    @Async("asyncTaskExecutor")
    public void ceshi2() {
        for (int i = 0; i <= 3; i  ) {
            log.info("ceshi2");
        }
    }
}    

4、测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class ThreadRunTest {
    @Autowired
    private ThreadTest t;
    @Test
    public void thread1() {
        for (int i = 1; i <= 10; i  ) {
            t.ceshi4();
        }
    }
}
@Component
@Slf4j
public class ThreadTest {
    @Async("asyncTaskExecutor")
    public void ceshi4() {
        log.info("ceshi4");
    }
}

四、总结

以上主要介绍了 ThreadPoolTaskExecutor 线程池的配置、使用、相关注解的意义及作用,也简单介绍了使用 @Async 来异步调用线程,最后又列举了多线程的使用场景,并配上了代码示例。这些仅为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring线程池ThreadPoolTaskExecutor配置详情

    本文介绍了Spring线程池ThreadPoolTaskExecutor配置,分享给大家,具体如下: 1. ThreadPoolTaskExecutor配置 <!-- spring thread pool executor --> <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <!-- 线

  • springboot使用线程池(ThreadPoolTaskExecutor)示例

    目录 线程池创建 线程池参数 线程池测试1(核心线程数量) 线程池测试2(当核心线程数量和最大线程数量不够时) 总结 代码仓库:gitee 线程池创建 @Configuration @EnableAsync public class TaskPoolConfig { @Bean("syncExecutorPool") public Executor taskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPool

  • Spring Boot利用@Async如何实现异步调用:自定义线程池

    前言 在之前的Spring Boot基础教程系列中,已经通过<Spring Boot中使用@Async实现异步调用>一文介绍过如何使用@Async注解来实现异步调用了.但是,对于这些异步执行的控制是我们保障自身应用健康的基本技能.本文我们就来学习一下,如果通过自定义线程池的方式来控制异步调用的并发. 本文中的例子我们可以在之前的例子基础上修改,也可以创建一个全新的Spring Boot项目来尝试. 定义线程池 第一步,先在Spring Boot主类中定义一个线程池,比如: @SpringBoo

  • spring boot使用自定义配置的线程池执行Async异步任务

    在前面的博客中,http://www.jb51.net/article/106718.htm 我们使用了spring boot的异步操作,当时,我们使用的是默认的线程池,但是,如果我们想根据项目来定制自己的线程池了,下面就来说说,如何定制线程池! 一.增加配置属性类 package com.chhliu.springboot.async.configuration; import org.springframework.boot.context.properties.ConfigurationP

  • Spring使用ThreadPoolTaskExecutor自定义线程池及异步调用方式

    目录 一.ThreadPoolTaskExecutor 1.将线程池用到的参数定义到配置文件中 2.Executors的工厂配置 2.1.配置详情 2.2.注解说明 2.3.线程池配置说明 2.4.线程池配置个人理解 二.异步调用线程 三.多线程使用场景 1.定时任务@Scheduled 2.程序一启动就异步执行多线程 3.定义一个http接口 4.测试类 四.总结 多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实

  • Java自定义线程池的实现示例

    目录 一.Java语言本身也是多线程,回顾Java创建线程方式如下: 二.JDK线程池工具类. 三.业界知名自定义线程池扩展使用. 一.Java语言本身也是多线程,回顾Java创建线程方式如下: 1.继承Thread类,(Thread类实现Runnable接口),来个类图加深印象. 2.实现Runnable接口实现无返回值.实现run()方法,啥时候run,黑话了. 3.实现Callable接口重写call()+FutureTask获取. public class CustomThread {

  • springboot为异步任务规划自定义线程池的实现

    目录 一.Spring Boot任务线程池 二.自定义线程池 三.优雅地关闭线程池 一.Spring Boot任务线程池 线程池的作用 防止资源占用无限的扩张 调用过程省去资源的创建和销毁所占用的时间 在高并发环境下,不断的分配新资源,可能导致系统资源耗尽.所以为了避免这个问题,我们为异步任务规划一个线程池.当然,如果没有配置线程池的话,springboot会自动配置一个ThreadPoolTaskExecutor 线程池到bean当中. # 核心线程数 spring.task.executio

  • Spring boot注解@Async线程池实例详解

    这篇文章主要介绍了Spring boot注解@Async线程池实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 从Spring3开始提供了@Async注解,该注解可以被标注在方法上,以便异步地调用该方法.调用者将在调用时立即返回,方法的实际执行将提交给Spring TaskExecutor的任务中,由指定的线程池中的线程执行. 1. TaskExecutor Spring异步线程池的接口类,其实质是java.util.concurrent

  • 关于dubbo 自定义线程池的问题

    目录 初识dubbo 一.什么是dubbo? 二.为什么要用dubbo 前言 dubbo线程池 dubbo线程池说明 自定义线程池代码实现步骤 初识dubbo 一.什么是dubbo? Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC(一种远程调用) 分布式服务框架(SOA),致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案,其实就是一种远程服务调用的分布式框架 二.为什么要用dubbo 在互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式

  • java多线程学习笔记之自定义线程池

    当我们使用 线程池的时候,可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其实我们深入到这些方法里面,就可以看到它们的是实现方式是这样的. public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueu

  • Android编程自定义线程池与用法示例

    本文实例讲述了Android编程自定义线程池与用法.分享给大家供大家参考,具体如下: 一.概述: 1.因为线程池是固定不变的,所以使用了单例模式 2.定义了两个线程池,长的与短的,分别用于不同的地方.因为使用了单例模式,所以定义两个. 3.定义了两个方法,执行的与取消的 二.代码: /** * @描述 线程管理池 * @项目名称 App_Shop * @包名 com.android.shop.manager * @类名 ThreadManager * @author chenlin * @dat

  • python自定义线程池控制线程数量的示例

    1.自定义线程池 import threading import Queue import time queue = Queue.Queue() def put_data_in_queue(): for i in xrange(10): queue.put(i) class MyThread(threading.Thread): def run(self): while not queue.empty(): sleep_times = queue.get() time.sleep(sleep_t

  • Python自定义线程池实现方法分析

    本文实例讲述了Python自定义线程池实现方法.分享给大家供大家参考,具体如下: 关于python的多线程,由与GIL的存在被广大群主所诟病,说python的多线程不是真正的多线程.但多线程处理IO密集的任务效率还是可以杠杠的. 我实现的这个线程池其实是根据银角的思路来实现的. 主要思路: 任务获取和执行: 1.任务加入队列,等待线程来获取并执行. 2.按需生成线程,每个线程循环取任务. 线程销毁: 1.获取任务是终止符时,线程停止. 2.线程池close()时,向任务队列加入和已生成线程等量的

随机推荐