Springboot的异步使用@Async

首先注意点:

1.在使用@Async注解时,调用方法和@Async标注方法不能在同一个类中,会造成异步失效。这种情况主要是因为:spring在加载Bean时,先扫描是否有@Async,如果有就用代理模式,将其代理,如果@Async加载在类上,就代理改类中所有方法,如果加载在方法上就代理该方法,在别的类调用时,实际上是调用的代理类,如果在本类中调用,实际上是用本类的调用,并没有调用代理类,所以异步不生效。

2.需要在启动类增加@EnableAsync注解。

3.在使用@Async注解时,要将类交给spring管理。

使用@Async标注异步,void无返回值

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

在使用@Async注解时可使用自定义线程池

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")

@Async使用Future接收返回值-长轮询案例

注意:在使用多线程异步操作时,因为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();

    }

你可能感兴趣的:(java,多线程)