spring boot+多线程实践(异步+返回值)

不扯淡了,直接开干,注意点在最后一定一定要看。 

在Springboot中对其进行了简化处理,只需要配置一个类型为java.util.concurrent.TaskExecutor或其子类的bean,并在配置类或直接在程序入口类上声明注解@EnableAsync

调用也简单,在由Spring管理的对象的方法上标注注解@Async,显式调用即可生效。

以下是一个带有返回值的异步线程任务示例: 

 配置类:

/**
 * @Description: 配置类实现AsyncConfigurer接口,并重写getAsyncExecutor方法,并返回一个ThreadPoolTaskExecutor,
 * 这样我们就获得一个基于线程池TaskExecutor
 * 利用@EnableAsync注解开启异步任务支持
 * @ClassName: MultiThreadingConfig
 * @Author: xiaolege
 */
@Configuration
@ComponentScan("com.cn.geostar.api.*")
@EnableAsync
public class MultiThreadingConfig implements AsyncConfigurer{

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //最小线程数
        taskExecutor.setCorePoolSize(5);
        //最大线程数
        taskExecutor.setMaxPoolSize(10);
        //等待队列
        taskExecutor.setQueueCapacity(50);
        taskExecutor.setKeepAliveSeconds(600);
        //设置拒绝策略
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //等待所有任务结束后再关闭线程池
//        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
    }
    
}

service:

/**
 * @author xiaolege
 */
@Service
@Slf4j
public class HarvestMultiThreadingService {

    /**
     * 表元数据信息采集
     *
     * @Description:通过@Async注解表明该方法是一个异步方法,
     * 如果注解在类级别上,则表明该类所有的方法都是异步方法,而这里的方法自动被注入使用ThreadPoolTaskExecutor作为TaskExecutor
     */
    @Async
    public Future<Boolean> executeAysncTableHarvest(BasicDataSource dataSource, String tableName){
        try{
            MetaLoader metaLoader = new MetaLoaderImpl(dataSource);
            Table tmd = metaLoader.getTable(tableName, SchemaInfoLevel.min());
            log.info(tmd.toString());
        } catch (Exception e){
            e.printStackTrace();
            return new AsyncResult<>(false);
        }
        //消息汇总
        return new AsyncResult<>(true);
    }
}

controller:

/**
 * @author xiaolege
 */
@RestController
@Slf4j
public class TableController {

    @Autowired
    private HarvestMultiThreadingService harvestMultiThreadingService;

    @PostMapping("getTableMeta")
    public GeoResponse getTableMeta(String dataSourceId) throws ExecutionException, InterruptedException {
//        GeoResponse geoResponse = harvestProvider.getDataSourceInfo(dataSourceId);
        String url = "jdbc:mysql://127.0.0.1:3306/ceshi?user=root&password=123456&serverTimezone=GMT%2b8";
        String tableName = "test";
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(url);
        dataSource.setMaxActive(20);
        dataSource.setInitialSize(5);
        dataSource.setMinIdle(5);
        dataSource.setMaxWait(60000);
        int length = 50;
        List<Future<Boolean>> list = new ArrayList<>(50);
        for (int i = 0; i < length; i++) {
            try {
                Future<Boolean> future = harvestMultiThreadingService.executeAysncTableHarvest(dataSource,tableName);
                list.add(future);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        for (Future f:list
             ) {
            log.info(f.get().toString());
        }
        return GeoResponse.defaultSuccess();
    }
}

注意: 

在java中提供了Future泛型接口,用来接收任务执行结果,springboot也提供了此类支持,使用实现了ListenableFuture接口的类如AsyncResult来作为返回值的载体。如上例所示。

如果不要返回值只需要把service里面的方法改为void返回即可。

有返回值的异步任务一定一定要注意

一定要批量读取结果, 否则不能达到异步的效果!!

1、异步方法和调用类不要在同一个类中

2、注解扫描时,要注意过滤,避免重复实例化,因为存在覆盖问题,@Async就失效了

猜你喜欢

转载自blog.csdn.net/xiaolegeaizy/article/details/108224319