Spring Async异步线程

版权声明:From Lay https://blog.csdn.net/Sadlay/article/details/86538065

Spring Async异步线程

TaskExecutor

Spring异步线程池的接口类,其实质是java.util.concurrent.Executor

Spring 已经实现的异常线程池:

  1. SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。
  2. SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方
  3. ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类
  4. SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类
  5. ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装

@Async

spring对过@Async定义异步任务

异步的方法有3种

  1. 最简单的异步调用,返回值为void
  2. 带参数的异步调用 异步方法可以传入参数
  3. 异常调用返回Future

详细见代码:

package com.lay.spring.async.service;

import org.springframework.scheduling.annotation.AsyncResult;

import java.util.concurrent.Future;

/**
 * @Description:
 * @Author: lay
 * @Date: Created in 14:07 2019/1/10
 * @Modified By:IntelliJ IDEA
 */
public interface AsyncService {

    /**
     * 简单的异步调用返回值为void
     */
    public void asyncInvokeSimple();

    /**
     * 带参数的异步调用,异步方法可以传入参数
     * 对于返回值是void,异常会被AsyncUncaughtExceptionHandler处理
     * @param param
     */
    public void asyncInvokeWtihParameter(String param);

    /**
     * 调用异常返回Future
     * 对于返回值是Future,不会被AsyncUncaughtExceptionHandler处理,需要我们在方法中捕获异常并处理
     * 或者在调用的Future.get时候捕获异常进行处理
     * @param i
     * @return
     */
    public Future<String> asyncInvokeReturnFuture(int i);

    /**
     * 通过AsyncResult捕获异常(有返回值)
     * AsyncResult是Future接口的子类,所以也可以通过future.get()获取返回值的时候捕获ExcecutionException
     * @param i
     * @return
     */
    public AsyncResult<String> asyncInvokeWithResult(int i);
}

具体实现类

package com.lay.spring.async.service.impl;

import com.lay.spring.async.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;

/**
 * @Description:
 * @Author: lay
 * @Date: Created in 14:12 2019/1/10
 * @Modified By:IntelliJ IDEA
 */


@Service
@Async("async-Executor")
public class AsyncServiceImpl implements AsyncService {
    private static final Logger log= LoggerFactory.getLogger(AsyncServiceImpl.class);

    @Override
    public void asyncInvokeSimple() {
        log.info("asyncInvokeSimple,线程{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId());
    }

    @Override
    public void asyncInvokeWtihParameter(String param) {
        log.info("asyncInvokeWtihParameter,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),param);
      
    }

    @Override
    public Future<String> asyncInvokeReturnFuture(int i) {
        log.info("asyncInvokeReturnFuture,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),i);
        Future<String> future=null;
        try {
            Thread.sleep(1000L);
            future=new AsyncResult<>("success:"+i);
        }catch (InterruptedException e){
            future=new AsyncResult<>("error");
        }
        return future;
    }

    @Override
    public AsyncResult<String> asyncInvokeWithResult(int i) {
        log.info("asyncInvokeWithResult,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),i);
        return new AsyncResult<>("success:"+i);
    }
}

Spring 开启异步配置

Spring有两种方法启动配置

  1. 注解
  2. XML

通过注解实现

要启动异常方法还需要以下配置

  1. @EnableAsync 此注解开户异步调用功能
  2. public AsyncTaskExecutor taskExecutor() 方法自定义自己的线程池,线程池前缀”Anno-Executor”。如果不定义,则使用系统默认的线程池。
package com.lay.spring.async.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * @Description:
 * @Author: lay
 * @Date: Created in 15:01 2019/1/10
 * @Modified By:IntelliJ IDEA
 */
@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean("async-Executor")
    public AsyncTaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("Async-Executor");
        executor.setMaxPoolSize(30);
        executor.setQueueCapacity(1000);
        executor.setCorePoolSize(10);
        executor.initialize();
        return executor;
    }
}

通过XML实现

 <!-- 等价于 @EnableAsync, executor指定线程池 -->
    <task:annotation-driven executor="xmlExecutor"/>
    <!-- id指定线程池产生线程名称的前缀 -->
    <task:executor
        id="xmlExecutor"
        pool-size="5-25"
        queue-capacity="100"
        keep-alive="120"
        rejection-policy="CALLER_RUNS"/>

测试类

package com.lay.spring.async;

import com.lay.spring.async.service.AsyncService;
import com.sun.media.jfxmedia.logging.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @Description:
 * @Author: lay
 * @Date: Created in 15:03 2019/1/10
 * @Modified By:IntelliJ IDEA
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class AsnycTest {

    @Autowired
    private AsyncService asyncService;
    @Test
    public void asyncTest(){
        Future<String> future=asyncService.asyncInvokeReturnFuture(100);
        asyncService.asyncInvokeSimple();
        asyncService.asyncInvokeWtihParameter("async-test");
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("InterruptedException ");
        } catch (ExecutionException e) {
            e.printStackTrace();
            System.out.println("ExecutionException ");
        }
        System.out.println("done");
    }
}

异步方法的异常处理

在调用方法时,可能出现方法中抛出异常的情况。在异步中主要有有两种异常处理方法:

  1. 对于方法返回值是Futrue的异步方法: a) 一种是在调用future的get时捕获异常; b) 在异常方法中直接捕获异常
  2. 对于返回值是void的异步方法:通过AsyncUncaughtExceptionHandler处理异常
package com.lay.spring.async.service.impl;

import com.lay.spring.async.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;

/**
 * @Description:
 * @Author: lay
 * @Date: Created in 14:12 2019/1/10
 * @Modified By:IntelliJ IDEA
 */


@Service
@Async("async-Executor")
public class AsyncServiceImpl implements AsyncService {
    private static final Logger log= LoggerFactory.getLogger(AsyncServiceImpl.class);

    @Override
    public void asyncInvokeSimple() {
        log.info("asyncInvokeSimple,线程{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId());
    }

    @Override
    public void asyncInvokeWtihParameter(String param) {
        log.info("asyncInvokeWtihParameter,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),param);
        throw new IllegalArgumentException(param);
    }

    @Override
    public Future<String> asyncInvokeReturnFuture(int i) {
        log.info("asyncInvokeReturnFuture,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),i);
        Future<String> future=null;
        try {
            Thread.sleep(1000L);
            future=new AsyncResult<>("success:"+i);
            throw new IllegalArgumentException("a");
        }catch (InterruptedException e){
            future=new AsyncResult<>("error");
        }
        return future;
    }

    @Override
    public AsyncResult<String> asyncInvokeWithResult(int i) {
        log.info("asyncInvokeWithResult,线程:{},参数:{}",Thread.currentThread().getName()+" "+Thread.currentThread().getId(),i);
        return new AsyncResult<>("success:"+i);
    }
}

实现AsyncConfigurer接口对异常线程池更加细粒度的控制

  • 创建线程自己的线程池
  • 对void方法抛出的异常处理的类AsyncUncaughtExceptionHandler
package com.lay.spring.async.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;

/**
 * @Description:
 * @Author: lay
 * @Date: Created in 15:39 2019/1/10
 * @Modified By:IntelliJ IDEA
 */
@Configuration
public class MyAsyncConfig implements AsyncConfigurer {
    private static final Logger log= LoggerFactory.getLogger(MyAsyncConfig.class);

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(1);
        threadPool.setMaxPoolSize(1);
        threadPool.setWaitForTasksToCompleteOnShutdown(true);
        threadPool.setAwaitTerminationSeconds(60 * 15);
        threadPool.setThreadNamePrefix("MyAsync-");
        threadPool.initialize();
        return threadPool;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new MyAsyncExceptionHandler();
    }

    class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
            log.info("Exception message - " + throwable.getMessage());
            log.info("Method name - " + method.getName());
            for (Object param : objects) {
                log.info("Parameter value - " + param);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Sadlay/article/details/86538065