异步与同步
同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。
异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。
常规的异步调用处理方式
在Java中,一般在处理类似的场景之时,都是基于创建独立的线程去完成相应的异步调用逻辑,
通过主线程和不同的线程之间的执行流程,从而在启动独立的线程之后,主线程继续执行而不会产生停滞等待的情况。
Spring中的@Async
在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,
将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。
分析
在spring中,通过任务执行器,也就是TaskExecutor来实现多线程和并发编程。
使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。
而实际开发中任务一般是非阻碍的,也就是非异步的,所以我们要在配置类中通过@EnableAsync开启对异步任务的支持,
并通过在实际执行的Bean的方法中使用@Async注解来声明其是一个异步任务。
配置任务执行器
/**
* 通过重写getAsyncExecutor方法,制定默认的任务执行由该方法产生
*
* 配置类实现AsyncConfigurer接口并重写getAsyncExcutor方法,并返回一个ThreadPoolTaskExevutor
* 这样我们就获得了一个基于线程池的TaskExecutor
*/
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(CORE_POOL_SIZE);// 线程池维护线程的最少数量
taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);// 线程池维护线程的最大数量
taskExecutor.setQueueCapacity(QUEUE_CAPACITY);// 线程池所使用的缓冲队列
taskExecutor.initialize();
return taskExecutor;
}
一、configuration包下的配置类,实现AsyncConfigurer接口
package com.liu.configuration;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 利用@EnableAsync注解开启异步任务支持
*/
@Configuration
@EnableAsync
public class TaskExecutorConfig implements AsyncConfigurer {
/**
* Set the ThreadPoolExecutor's core pool size.
*/
private static final int CORE_POOL_SIZE = 5;
/**
* Set the ThreadPoolExecutor's maximum pool size.
*/
private static final int MAX_POOL_SIZE = 20;
/**
* Set the capacity for the ThreadPoolExecutor's BlockingQueue.
*/
private static final int QUEUE_CAPACITY = 10;
/**
* 通过重写getAsyncExecutor方法,制定默认的任务执行由该方法产生
*
* 配置类实现AsyncConfigurer接口并重写getAsyncExcutor方法,并返回一个ThreadPoolTaskExevutor
* 这样我们就获得了一个基于线程池的TaskExecutor
*/
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 线程池维护线程的最少数量
taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
// 线程池维护线程的最大数量
taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
// 线程池所使用的缓冲队列
taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
/**
* 自定义任务执行器:在定义了多个任务执行器的情况下,可以使用@Async("getMineAsync")来设定
*
* @return
*/
@Bean
public Executor getMineAsync() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(CORE_POOL_SIZE - 4);
executor.setMaxPoolSize(MAX_POOL_SIZE - 10);
executor.setQueueCapacity(QUEUE_CAPACITY - 5);
executor.setThreadNamePrefix("mineAsync-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
二、业务层
package com.liu.service;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
/**
* 操作计算 service 类:简单实现有关异步和同步两种计算方式的性能比较
*/
@Component
public class ArithmeticService {
private final static Logger logger = LoggerFactory.getLogger(ArithmeticService.class);
public static final int DoTime = 5000;
/**
* 异步任务 只需要在所需实现异步的方法上加上@Async注解, 并通过Future<T>来接受异步方法的处理结果
* 通过@Async注解表明该方法是个异步方法,如果注解在类级别,则表明该类所有的方法都是异步方法
*
* @return
*/
@Async
public Future<Long> subByAsync() throws Exception {
long start = System.currentTimeMillis();
long sum = 0;
Thread.sleep(DoTime);
long end = System.currentTimeMillis();
sum = end - start;
logger.info("/t 完成任务一");
return new AsyncResult<>(sum);
}
/**
* 仅使用异步注解的方式实现异步方法
*
* @return
*/
@Async
public void subByVoid() throws Exception {
long start = System.currentTimeMillis();
long sum = 0;
Thread.sleep(DoTime);
long end = System.currentTimeMillis();
sum = end - start;
logger.info("/t 完成任务二 ");
logger.info("注解任务执行的时间是: " + sum + "(毫秒)");
}
/**
* 使用同步计算的方式--同步调用
*
* @return
*/
public long subBySync() throws Exception {
long start = System.currentTimeMillis();
long sum = 0;
Thread.sleep(DoTime);
long end = System.currentTimeMillis();
sum = end - start;
logger.info("/t 完成任务三 ");
return sum;
}
@Async("getMineAsync")
public void doMineAsync(int i) throws Exception {
System.out.println("------/t:" + i);
Thread.sleep(10000);
}
}
三、controller层代码
package com.liu.controller;
import java.util.concurrent.Future;
import com.liu.service.ArithmeticService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/async")
public class IndexController {
private final static Logger logger = LoggerFactory.getLogger(IndexController.class);
@Autowired
private ArithmeticService arithmeticService;
@GetMapping("/test1")
public void index() {
long start = System.currentTimeMillis();
try {
logger.info("--------------------------------------------/n");
logger.info("每个任务执行的时间是:" + arithmeticService.DoTime + "(毫秒)");
Future<Long> task = arithmeticService.subByAsync();
arithmeticService.subByVoid();
long sync = arithmeticService.subBySync();
while (true) {
if (task.isDone()) {
long async = task.get();
logger.info("异步任务执行的时间是:" + async + "(毫秒)");
// logger.info("注解任务执行的时间是: -- (毫秒)");
logger.info("同步任务执行的时间是:" + sync + "(毫秒)");
break;
}
}
logger.info("--------------------------------------------/n");
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
logger.info("/t........请求响应时间为:" + (end - start) + "(毫秒)");
}
/**
* 自定义实现线程异步
*/
@GetMapping("/test2")
public void mineAsync() {
for (int i = 0; i < 100; i++) {
try {
arithmeticService.doMineAsync(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/281677.html