异步的编程规范

异步的概念和定义、请自行查阅,本文不再赘述。下面主要讲解异步的使用方法,和异步使用中需要注意的地方。

如何使用异步

以下是一个JAVA SpringBoot应用,使用@Async注解(该注解由spring提供)实现异步方法的具体过程。
1、首先创建线程池,这里需要注意的是,在项目的启动类上也需要添加@EnableAsync

@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {

/**
 *   默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,
 *    当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
 *  当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
 */

    /** 核心线程数(默认线程数) */
    private static final int corePoolSize = 20;
    /** 最大线程数 */
    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 taskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveTime);
        executor.setThreadNamePrefix(threadNamePrefix);

        // 线程池对拒绝任务的处理策略
        // CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }
}

2、在需要被异步执行的方法上添加 @Async 注解,

@Service
public class TranTest2Service {
    Logger log = LoggerFactory.getLogger(TranTest2Service.class);

    // 发送提醒短信 1
    @Async("taskExecutor")
    public void sendMessage1() throws InterruptedException {
        log.info("发送短信方法---- 1   执行开始");
        // 模拟耗时
        Thread.sleep(3000);
        log.info("发送短信方法---- 1   执行结束");
    }

    // 发送提醒短信 2
    @Async("taskExecutor")
    public void sendMessage2() throws InterruptedException {
        log.info("发送短信方法---- 2   执行开始");
        Thread.sleep(2000);
        log.info("发送短信方法---- 2   执行结束");
    }

    @Async("taskExecutor")
    public Future<String> sendMessage3(Integer num) throws InterruptedException {
        log.info("发送短信方法---- 3   执行开始" + num);
        Thread.sleep(new Random().nextInt(10000) + 1000);
        log.info("发送短信方法---- 3   执行结束" + num);
        return new AsyncResult("sendMessage3  : I am method");
    }
}

3、在另外一个类中调用上述异步方法。

@Service
public class OrderTaskServic {
    @Resource
    private TranTest2Service tranTest2Service;

    // 订单处理任务
    public void orderTask() throws InterruptedException, ExecutionException {


        tranTest2Service.sendMessage1(); // 发短信的方法   1
        tranTest2Service.sendMessage2(); // 发短信的方法  2
        this.cancelOrder(); // 取消订单

        List<Future<String>> futureList = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 20; i++) {
            Future<String> result = tranTest2Service.sendMessage3(i);
            futureList.add(result);
        }

        while (true) {
            int acount = 0;
            int size = futureList.size();
            for (Future<String> result : futureList) {
                if (result.isDone()) {
                    acount++;
                    System.out.println(result.get());
                    futureList.remove(result);
                }
            }
            if (acount == size) {
                break;
            }
            Thread.sleep(1000);
        }
    }

    // 取消订单
    public void cancelOrder() throws InterruptedException {
        System.out.println("取消订单的方法执行------开始");
        System.out.println("取消订单的方法执行------结束 ");
    }

}

4、测试一下

@SpringBootTest
@EnableAsync
class DemoApplicationTests {

    @Resource
    private OrderTaskServic orderTaskServic;

    @Test
    void contextLoads() {
        System.out.println("XXXXXXXX");
        try {
            orderTaskServic.orderTask();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

}

另外如果需要拿到异步方法的执行结果,可以使用Future<>结合Future.isDone来实现。

你可能感兴趣的:(spring,boot,java,spring)