Java如何实现异步处理

3,269 阅读2分钟

在实际项目当中,经常用到异步处理,今天利用周末时间总结一下。

一、同步调用和异步处理的区别:

同步调用:整个处理过程按顺序执行,每一步必须等到上一步执行完后才能执行
异步调用:只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕,继续执行下面的流程。

异步实现方式

方式一:

1.  new Thread((new Runnable() {
1.  @Override
1.  public void run() {
1.  // 批量同步数据
1.  try {
1.  logger.info("^^^^^^^^^^^^^^^^^ sync start ^^^^^^^^^^^^^^^^^ ");
1.
1.  logger.info("^^^^^^^^^^^^^^^^^ sync end ^^^^^^^^^^^^^^^^^ ");
1.  } catch (IOException e) {
1.  LogUtils2.error("", e);
1.  }
1.  }
1.  })).start();

方式2:

private ExecutorService executor = Executors.newFixedThreadPool(1);
 executor.submit(new Runnable() {
  @Override
  public void run() {
  // 批量同步数据
  try {
  logger.info("^^^^^^^^^^^^^^^^^ sync weinxi data start ^^^^^^^^^^^^^^^^^ ");
      weiXinUsersService.batchSaveHandle();
     logger.info("^^^^^^^^^^^^^^^^^ sync weinxi data end ^^^^^^^^^^^^^^^^^ ");
      } catch (IOException e) {
      LogUtils2.error("", e);
      }
     }
});

方式3:@EnableAsync和@Async注解

  • 异步注解 @EnableAsync :开启异步方法的支持
  • @Async 异步方法
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AsyncConfigurationSelector.class})
public @interface EnableAsync {
    Class<? extends Annotation> annotation() default Annotation.class;

    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default 2147483647;
}

@EnableAsync用于开启异步方法的支持。只有开启了异步方法的支持才可以使用@Async`。

一、开启异步:@ENABLEASYNC

@EnableAsync 
@SpringBootApplication 
public class Application { 

public static void main(String[] args) 
    {
    SpringApplication.run(Application.class, args); 
   } 
 }

@EnableAsync可以让Spring启用异步方法执行,就跟在xml中配置task:* 效果是一样的。它可以跟@Configuration结合,让整个Spring环境启用基于注解的异步处理:

import java.util.concurrent.Executor;

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 com.google.gson.Gson;
import com.google.gson.GsonBuilder;

@Configuration
@EnableAsync
@SuppressWarnings(value = "Duplicates")
public class AppConfig {

    public static final String ASYNC_EXECUTOR_NAME = "asyncExecutor";

    @Bean(name=ASYNC_EXECUTOR_NAME)
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // for passing in request scope context
        executor.setTaskDecorator(new ContextCopyingDecorator());
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(100);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setThreadNamePrefix("AsyncThread-");
        executor.initialize();
        return executor;
    }
    
    @Bean
   public Gson gson() {
      return new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
   }

为什么要给@ASYNC自定义线程池?

@Async注解,在默认情况下用的是SimpleAsyncTaskExecutor线程池,该线程池不是真正意义上的线程池,因为线程不重用,每次调用都会新建一条线程。

@Async注解异步框架提供多种线程

SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。

SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方

ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类

ThreadPoolTaskScheduler:可以使用cron表达式

ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装

举例:


    @EnableAsync
    public class WeiXinUsersService extends BaseGongfuService {

    @Async
    public void batchSaveHandle() throws IOException 
    
     }
}

@Async`可以把某一个方法或者类下面的方法全部变成异步处理的方法。

参考文章