1.在使用@Async注解时,调用方法和@Async标注方法不能在同一个类中,会造成异步失效。这种情况主要是因为:spring在加载Bean时,先扫描是否有@Async,如果有就用代理模式,将其代理,如果@Async加载在类上,就代理改类中所有方法,如果加载在方法上就代理该方法,在别的类调用时,实际上是调用的代理类,如果在本类中调用,实际上是用本类的调用,并没有调用代理类,所以异步不生效。
2.需要在启动类增加@EnableAsync注解。
3.在使用@Async注解时,要将类交给spring管理。
1.在启动类中加@EnableAsync注解
@SpringBootApplication
@EnableAsync
public class ThreadApplication {
public static void main(String[] args) {
SpringApplication.run(ThreadApplication.class, args);
}
}
2.在使用方法中加@Async注解
@Override
@Async
public void ayncFuture(Integer num) throws InterruptedException {
StringBuilder sb = new StringBuilder();
for(int i=0;i<=num;i++){
System.out.println(i);
sb.append(i);
System.out.println(Thread.currentThread().toString());
Thread.sleep(100);
}
System.out.println(sb);
}
3.模拟异步调用
public void test(){
try{
ayncService.ayncFuture(5);
ayncService.ayncFuture(6);
}catch (Exception e){
e.getCause();
}
}
4.调用结果
0
Thread[async-service-1,5,main]
0
Thread[async-service-2,5,main]
1
Thread[async-service-1,5,main]
1
Thread[async-service-2,5,main]
2
2
Thread[async-service-1,5,main]
Thread[async-service-2,5,main]
3
Thread[async-service-2,5,main]
3
Thread[async-service-1,5,main]
4
4
Thread[async-service-1,5,main]
Thread[async-service-2,5,main]
5
5
Thread[async-service-1,5,main]
Thread[async-service-2,5,main]
6
012345
Thread[async-service-2,5,main]
0123456
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class threadPool {
@Bean("AsyncServiceExecutor")
public Executor AsyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(5);
//配置最大线程数
executor.setMaxPoolSize(100);
//配置队列大小
executor.setQueueCapacity(100);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-service-");
// 设置拒绝策略:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
使用形式:@Async("AsyncServiceExecutor")
注意:在使用多线程异步操作时,因为spring默认为单例模式,所以在调用异步方法如果处理了类的成员变量,要考虑到是使用单例还是多例
import com.white.thread.test.services.AyncService;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AyncServiceImpl implements AyncService {
private Integer i = 10;
@Override
@Async
public void ayncFuture(Integer num) throws InterruptedException {
StringBuilder sb = new StringBuilder();
for(int i=0;i<=num;i++){
System.out.println(i);
sb.append(i);
System.out.println(Thread.currentThread().toString());
Thread.sleep(100);
}
System.out.println(sb);
}
@Override
@Async("AsyncServiceExecutor")
public Future ayncFutureDefualt() throws InterruptedException {
while(true){
System.out.println(i+"轮询中...");
synchronized (this) {
if (i == 0) {
return new AsyncResult(i);
}
i--;
}
Thread.sleep(100);
}
}
}
其中轮询次数是根据类的成员变量来设置,这里要设置多例,如果是单例情况就会调用一次修改后后续成员变量被修改无法轮询:使用多例时:@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS) 用此标注,如果使用@Scope("prototype")会出现失效情况
AsyncResult是Future的子类
public String test2(){
Future result = null;
Future result2 = null;
Integer msg = null;
try{
result=ayncService.ayncFutureDefualt();
result2=ayncService.ayncFutureDefualt();
msg = result.get(50, TimeUnit.SECONDS);
}catch (TimeoutException e){
//logger.warn(String.format("长轮询用户{%s}超时...",userId.toString()));
//e.printStackTrace();
System.out.println("超时");
}catch(Exception e1){
//logger.error(String.format("长轮询用户{%s}异常...",userId.toString()),e1);
System.out.println("出错");
e1.printStackTrace();
}
finally {
if (result != null){
result.cancel(true);
}
}
return msg.toString();
}