Spring 环境多线程使用分析


在原生Java代码中使用多线程的时候,往往需要创建Thread类,或者实现Runnable接口,如果要使用到线程池,还需要来创建Executors。在spring中,对线程的使用做了很好的支持。只要@EnableAsync就可以使用多线程。使用@Async就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线程池。 默认情况下,Spring将搜索相关的线程池定义:要么在上下文中搜索唯一的TaskExecutor bean,要么搜索名为“taskExecutor”的Executor bean。如果两者都无法解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用。

定义配置类

@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
    
    private static final int corePoolSize = 10;              // 核心线程数(默认线程数)
    private static final int maxPoolSize = 100;              // 最大线程数
    private static final int keepAliveTime = 10;            // 允许线程空闲时间(单位:默认为秒)
    private static final int queueCapacity = 200;           // 缓冲队列数
    private static final String threadNamePrefix = "Async-Service-"; // 线程池名前缀
    
    @Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
    public ThreadPoolTaskExecutor getAsyncExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);   
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveTime);
        executor.setThreadNamePrefix(threadNamePrefix);
        
        // 线程池对拒绝任务的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }
}
@Configuration用于定义配置类,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。@EnableAsync开始对异步任务的支持。 线程池的配置还有一种方式,直接实现AsyncConfigurer接口,重写getAsyncExecutor方法即可。
@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {

     @Override
     public Executor getAsyncExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setCorePoolSize(7);
         executor.setMaxPoolSize(42);
         executor.setQueueCapacity(11);
         executor.setThreadNamePrefix("MyExecutor-");
         executor.initialize();
         return executor;
     }

     @Override
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return new MyAsyncUncaughtExceptionHandler();
     }
}

定义使用类

@Service
public class testAsyncService {
    Logger log = LoggerFactory.getLogger(testAsyncService.class);
 
    // 发送提醒短信 1
    @Async("taskExecutor")
    public void service1() throws InterruptedException {
        log.info("--------start-service1------------");
        Thread.sleep(5000); // 模拟耗时
        log.info("--------end-service1------------");
    }
    
    // 发送提醒短信 2
    @Async("taskExecutor")
    public void service2() throws InterruptedException {
        
        log.info("--------start-service2------------");
        Thread.sleep(2000); // 模拟耗时
        log.info("--------end-service2------------");
 
    }
}
@Async注解来声明一个或多个异步任务,可以加在方法或者类上,加在类上表示这整个类都是使用这个自定义线程池进行操作。接着我们可以创建control类@Autowired这个service并且调用这其中两个方法,进行连续调用,运行结果如下:
--------start-service1------------
--------start-service2------------
--------end-service2------------
--------end-service1------------

@Async失效情况

  • 异步方法使用static修饰
  • 异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
  • 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
  • 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
  • 在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效。
  • 调用被@Async标记的方法的调用者不能和被调用的方法在同一类中不然不会起作用
  • 使用注解@Async的返回值只能为void或者Future及其子类,当返回结果为其他类型时,方法还是会异步执行,但是返回值都是null。

相关