当前位置: 首页 > 图灵资讯 > 技术篇> 线程池使用方式

线程池使用方式

来源:图灵教育
时间:2023-06-27 15:06:06

@Async+Asyncconfigurer重新实现自定义线程池配置类。

@Configuration public class AsyncConfiguration implements AsyncConfigurer {     @Bean("kingAsyncExecutor")     public ThreadPoolTaskExecutor executor() {         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();         int corePoolSize = 10;         executor.setCorePoolSize(corePoolSize);         int maxPoolSize = 50;         executor.setMaxPoolSize(maxPoolSize);         int queueCapacity = 10;         executor.setQueueCapacity(queueCapacity);         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());         String threadNamePrefix = "kingDeeAsyncExecutor-";         executor.setThreadNamePrefix(threadNamePrefix);         executor.setWaitForTasksToCompleteOnShutdown(true);         // 使用自定义跨线程的要求级别线程工厂类19         int awaitTerminationSeconds = 5;         executor.setAwaitTerminationSeconds(awaitTerminationSeconds);         executor.initialize();         return executor;     }      @Override     public Executor getAsyncExecutor() {         return executor();     }      @Override     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {         return (ex, method, params) -> ErrorLogger.getInstance().log(String.format(”执行异步任务的%s'", method), ex);     } }

继承AsynconfigurerSupport

@Configuration  @EnableAsync  class SpringAsyncConfigurer extends AsyncConfigurerSupport {        @Bean      public ThreadPoolTaskExecutor asyncExecutor() {          ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();          threadPool.setCorePoolSize(3);          threadPool.setMaxPoolSize(3);          threadPool.setWaitForTasksToCompleteOnShutdown(true);          threadPool.setAwaitTerminationSeconds(60 * 15);          return threadPool;      }        @Override      public Executor getAsyncExecutor() {          return asyncExecutor;  }    @Override      public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {    return (ex, method, params) -> ErrorLogger.getInstance().log(String.format(”执行异步任务的%s'", method), ex);}}

由自定义Taskexecutor代替内置任务执行器

@EnableAsync @Configuration public class TaskPoolConfig {     @Bean(name = AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME)     public Executor taskExecutor() {         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();          //核心线程池大小         executor.setCorePoolSize(10);         ////最大线程数         executor.setMaxPoolSize(20);         ////队列容量         executor.setQueueCapacity(200);         //活跃时间         executor.setKeepAliveSeconds(60);         ///线程名前缀         executor.setThreadNamePrefix("taskExecutor-");         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());         return executor;     }    @Bean(name = "new_task")     public Executor taskExecutor() {         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();          //核心线程池大小         executor.setCorePoolSize(10);         ////最大线程数         executor.setMaxPoolSize(20);         ////队列容量         executor.setQueueCapacity(200);         //活跃时间         executor.setKeepAliveSeconds(60);         ///线程名前缀         executor.setThreadNamePrefix("taskExecutor-");         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());         return executor;     } }

@Async失效
  • 使用static修改异步法
  • 不使用@Component注释(或其他注释)导致spring无法扫描异步类
  • 异步法不能与被调用的异步法相同
  • 需要使用@Autowired或@resource等注解自动注入,不能手动注入new对象
  • 如果使用SpringBoot框架,则必须在启动类中添加@Enableasync注释
@Async使用场景

@Async注释的主要功能是实现异步法的调用。它可以将一种方法的执行委托给线程池中的线程进行异步执行,以免堵塞当前线程。

@Async实际使用场景包括但不限于以下几个方面:

  1. 提高系统的并发性能力:通过异步化耗时的操作,可以提高系统的并发性能力。例如,在Web应用程序中,可以标记一些耗时的操作(如发送电子邮件、生成报告等)@Async,这样可以避免堵塞主线程,增加系统的吞吐量。
  2. 改善用户体验:可用于上传文件、数据处理等需要耗时操作的场景@Async实现异步处理,从而提升用户体验。用户可以在不等待耗时操作的情况下继续进行其他操作。
  3. 避免堵塞调用方:有时,调用方不希望等待方法的执行结果,而是希望立即返回。使用@Async该方法的执行可以转移到异步线程中,以避免阻塞调用方。
  4. 并行执行任务:在某些情况下,不等待执行结果,需要同时执行多个任务。使用@Async这些任务可以标记为异步法,它们可以并行执行,从而提高效率。
注意

因为 Spring 同一类别中的方法调用不会通过代理对象实现异步执行。在同一类别中,方法调用是直接的普通方法调用,不会被代理拦截。

因此,如果一个被直接调用到同一类别中@Async该方法将在当前线程中同步执行,而不是异步执行。这可能会影响您预期的异步执行效果。

为保证异步法的异步实施,应将异步法从同一类中剥离出来,并利用外部或其他类调用异步法。这样,Spring 异步法的调用将通过代理对象截获,并委托给异步线程池执行,从而达到异步执行的效果。

综上所述,如果异步法直接在同一类中调用,则该方法将在当前线程中同步执行。为了达到异步执行的效果,应通过外部或其他类别调用异步法。

@Async+自定义线程+配置类

1、创建一个自定义的线程池,继承自己java.util.concurrent.ThreadPoolExecutor或实现java.util.concurrent.Executor接口,根据需要定制线程池的配置,如核心线程数、最大线程数、队列容量等。

import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class MyThreadPool {    private ThreadPoolExecutor executor;    public MyThreadPool() {        int corePoolSize = 10;        int maxPoolSize = 20;        int queueCapacity = 50;        executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(queueCapacity));    }    public ThreadPoolExecutor getExecutor() {        return executor;    }}

2、Spring 在Boot的配置类别中创建一个@Bean,返回自定义的线程池实例。

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class AppConfig {    @Bean    public MyThreadPool myThreadPool() {        return new MyThreadPool();    }}

3、使用需要异步执行的方法@Async并使用注释executor属性指定自定义的线程池。

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Servicepublic class MyService {    private MyThreadPool myThreadPool;    @Autowired    public MyService(MyThreadPool myThreadPool) {        this.myThreadPool = myThreadPool;    }    @Async(executor = "myThreadPool")    public void asyncMethod() {        // 异步执行的逻辑        // ...    }}

手动控制线程池

1、创建一个可以继承自定义的线程池java.util.concurrent.ThreadPoolExecutor或实现java.util.concurrent.Executor接口,根据需要定制线程池的配置。

import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class MyThreadPool {    private ThreadPoolExecutor executor;    public MyThreadPool() {        int corePoolSize = 10;        int maxPoolSize = 20;        int queueCapacity = 50;        executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(queueCapacity));    }    public void execute(Runnable task) {        executor.execute(task);    }}

2、在需要异步执行的方法中,创建了实现的方法Runnable并将接口的任务提交给自定义线程池执行。

public class MyClass {    private MyThreadPool myThreadPool;    public MyClass(MyThreadPool myThreadPool) {        this.myThreadPool = myThreadPool;    }    public void myMethod() {        // 实现Runnnable接口任务的创建        Runnable task = () -> {            // 异步执行的逻辑            // ...        };        // 提交给自定义线程池的任务        myThreadPool.execute(task);    }}