南飓风 发表于 2023-5-24 19:06:35

Java开启异步的两种方式

二、Java开启异步的两种方式

1、注解开启:@Async

1.1、配置异步的线程池


[*]必须配置异步线程池,否则异步不会生效。
[*]@EnableAsync 注解:指定异步线程池。不指定默认使用:SimpleAsyncTaskExecutor线程池
[*]SimpleAsyncTaskExecutor是一个最简单的线程池,它没有任何的线程相关参数配置,它会为每个任务创建一个新的线程来执行,因此不建议在生产环境中使用。
[*]配置线程池见:https://www.cnblogs.com/kakarotto-chen/p/17428432.html
package com.cc.md.config;

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;

/** IO型的线程池
* @author CC
* @since 2023/5/23 0023
*/
@Configuration
@EnableAsync
public class IoThreadPool {

    public static final int THREAD_SIZE = 2 * (Runtime.getRuntime().availableProcessors());
   
    public static final int QUEUE_SIZE = 1000;

    @Bean(name = "myIoThreadPool")
    public ThreadPoolTaskExecutor threadPoolExecutor(){
      ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
      executor.setCorePoolSize(THREAD_SIZE);
      executor.setMaxPoolSize(THREAD_SIZE);
      executor.setQueueCapacity(QUEUE_SIZE);
      executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
      executor.setKeepAliveSeconds(60);
      executor.setAllowCoreThreadTimeOut(true);
      executor.setAwaitTerminationSeconds(300);
      executor.setWaitForTasksToCompleteOnShutdown(true);
      executor.setThreadNamePrefix("myIo-Th-Pool-");
      executor.initialize();
      return executor;
    }
}1.2、异步方法


[*]异步方法必须写在另一个类中,否则不生效
[*]@Async可以打在类上、也可以打在方法上
    1 @Async:类上,说明整个类中的方法都是异步。必须写我们自己配置的线程池 —— ("myIoThreadPool")
    2 @Async:方法上,说明这个方法是异步。不用写我们自己配置的线程池

[*]异步接口+实现类
接口
package com.cc.md.service;

/**
* @author CC
* @since 2023/5/24 0024
*/
public interface IAsyncService {

    /** 异步方法1
   * @since 2023/5/24 0024
   * @author CC
   **/
    void async1();

    /** 异步方法2
   * @since 2023/5/24 0024
   * @author CC
   **/
    void async2();

}实现类
package com.cc.md.service.impl;

import com.cc.md.service.IAsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/** 1 @Async:类上,说明整个类中的方法都是异步。必须写我们自己配置的线程池 —— ("myIoThreadPool")
*2 @Async:方法上,说明这个方法是异步。不用写我们自己配置的线程池
* @author CC
* @since 2023/5/24 0024
*/
@Service
@Async("myIoThreadPool")
public class AsyncServiceImpl implements IAsyncService {

    private static final Logger log = LoggerFactory.getLogger(AsyncServiceImpl.class);

    //类上写了@Async,这里就可以不写了。
    //可以不写 ("myIoThreadPool")。因为在IoThreadPool中开启了异步,说明异步用的就是我们配置的io线程池
    //如果类上面打了 @Async ,这里必须写:("myIoThreadPool")
    @Override
    //@Async
    public void async1(){
      //模仿io流耗时
      try {
            Thread.sleep(5000);
      } catch (InterruptedException e) {
            throw new RuntimeException(e);
      }
      log.info("打印:{}", "异步方法1111!");
    }

    //@Async在类上面,说明这个方法也是异步方法。如果不打,无法开启异步。
    @Override
    public void async2(){
      //模仿io流耗时
      try {
            Thread.sleep(5000);
      } catch (InterruptedException e) {
            throw new RuntimeException(e);
      }
      log.info("打印:{}", "异步方法2222!");
    }
}1.3、测试

    @Resource
    private IAsyncService asyncService;
   
    //开启异步1 —— @Async
    @Test
    public void test03() throws Exception {
      log.info("打印:{}", "异步测试的-主方法1");
      asyncService.async1();
      asyncService.async2();
      //不会等待异步方法执行,直接返回前端数据
      log.info("打印:{}", "异步测试的-主方法2");
    }结果:
https://img2023.cnblogs.com/blog/1848807/202305/1848807-20230524160154595-283198904.png
2、CompletableFuture的方式

使用:
    @Resource(name = "myIoThreadPool")
    private ThreadPoolTaskExecutor myIoThreadPool;
   
    //开启异步2 —— CompletableFuture.runAsync()
    @Test
    public void test04() throws Exception {
      log.info("打印:{}", "异步测试的-主方法1");
      CompletableFuture.runAsync(() -> {
            log.info("打印:{}", "异步方法1!");
            //异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
            this.async2("异步方法1!-end");
      }, myIoThreadPool);
      //不会等待异步方法执行,直接返回前端数据
      log.info("打印:{}", "异步测试的-主方法2");
    }

    //异步需要执行的方法,可以写在同一个类中。
    private void async2(String msg) {
      //模仿io流耗时
      try {
            Thread.sleep(5000);
      } catch (InterruptedException e) {
            throw new RuntimeException(e);
      }
      log.info("打印:{}", msg);
    }结果:
https://img2023.cnblogs.com/blog/1848807/202305/1848807-20230524160209809-270757067.png

[*]后续CompletableFuture的使用见:《Java的CompletableFuture,Java的多线程开发》

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Java开启异步的两种方式