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"); | |
} |
结果:
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); | |
} |
结果:
- 后续CompletableFuture的使用见:《Java的CompletableFuture,Java的多线程开发》