java asyncexec_Spring @Async 注解的使用

使用前提

假如当前类 a.class 中有异步方法,并使用了@Async,那么必须由其他类(例如b.class)来调用,不可由其本身(a.class)来调用;

该方法必须是public 且无返回值,即:

@Async

public void asyncMethod(){

}

需要注意

在和事务一起使用的时候,即调用这个异步方法的方法上使用了@Transactional注解。

a.class

@Async

public void asyncMethod(){

}

b.class

@Transactional

public void fun(){

//...

a.asyncMethod();

//...

}

此时事务会有问题,因为a会新起一个线程来执行asyncMethod(),所以a与fun()不是一个事务,会导致数据不一致。

2.需要为异步配置线程池

如下

package com.fanneng.spring.config;

import lombok.Getter;

import lombok.Setter;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.scheduling.annotation.EnableAsync;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**

* Created by feifan.gou@gmail.com on 2019/11/29 20:00.

*/

@Configuration

@EnableAsync

public class ThreadPoolConfig {

@Autowired

private ThreadPoolProperty poolProperty;

@Bean

public ThreadPoolTaskExecutor taskExecutor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

/* 最大线程数 */

executor.setMaxPoolSize(poolProperty.maxPoolSize);

/* 核心线程数 */

executor.setCorePoolSize(poolProperty.corePoolSize);

/* 队列最大长度 */

executor.setQueueCapacity(poolProperty.queueCapacity);

/* 线程名称前缀 */

executor.setThreadNamePrefix(poolProperty.threadNamePrefix);

/* 拒绝策略 */

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

executor.initialize();

return executor;

}

@Getter

@Setter

@Configuration

@ConfigurationProperties(prefix = "executor.thread.pool")

public static class ThreadPoolProperty {

private int corePoolSize;

private int maxPoolSize;

private int queueCapacity;

private String threadNamePrefix;

}

/* 拒绝策略说明(当pool已经达到max size的时候,如何处理新任务):

* ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

* ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。

* ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)

* ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

*/

}

在注入ThreadPoolTaskExecutor的时候需要注意

public ThreadPoolTaskExecutor taskExecutor()中的方法名默认是taskExecutor,那么意味着bean的名称也是taskExecutor,那么在使用@Async的时候,会默认去该线程池那线程;

为啥默认是taskExecutor呢? 请看spring源码 TaskExecutionAutoConfiguration.java 84行:ee3fe1630ab2492d74e35a9422c74da1.png

如果起了其他的名称,也就是bean是其他名称,那么在使用@Async的时候需要指定线程池的名称;例如bean的名称是 asyncExector ,那么使用@Async的时候应该是

@Async("asyncExector")

public void asyncMethod(){

}

否则会去默认使用 SimpleAsyncTaskExecutor。

附上spring 中 TaskExecutor 的常用几个实现

名字

特点

SimpleAsyncTaskExecutor

每次请求新开线程,没有最大线程数设置.不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。 --【1】

SyncTaskExecutor

不是异步的线程.同步可以用SyncTaskExecutor,但这个可以说不算一个线程池,因为还在原线程执行。这个类没有实现异步调用,只是一个同步操作。

ConcurrentTaskExecutor

Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类。

SimpleThreadPoolTaskExecutor

监听Spring’s lifecycle callbacks,并且可以和Quartz的Component兼容.是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类。

ThreadPoolTaskExecutor

最常用。要求jdk版本大于等于5。可以在程序而不是xml里修改线程池的配置.其实质是对java.util.concurrent.ThreadPoolExecutor的包装。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值