乐趣区

关于java:Async的用法和示例

@Async 注解的用法和示例

[TOC]

背景

通常,在 Java 中的办法调用都是同步调用,比方在 A 办法中调用了 B 办法,则在 A 调用 B 办法之后,必须期待 B 办法执行并返回后,A办法才能够持续往下执行。这样容易呈现的一个问题就是如果 B 办法执行工夫较长,则可能会导致调用 A 的申请响应缓慢,为了解决这种问题,能够应用 Spirng 的注解 @Async 来用异步调用的形式解决,当然也会有别的多线程形式解决此类问题,本文次要剖析 @Async 在解决此类问题时的用法以及具体的示例。

异步调用

比方办法 A 调用办法 B,如果B 是一个异步办法,则 A 办法在调用 B 办法之后,不必期待 B 办法执行实现,而是间接往下继续执行别的代码。

@Async 介绍

在 Spring 中,应用 @Async 标注某办法,能够使该办法变成异步办法,这些办法在被调用的时候,将会在独立的线程中进行执行,调用者不需期待该办法执行实现。

在 Spring 中启用 @Async

应用@EnableAsync

@Slf4j
@SpringBootApplication
@ComponentScan(basePackages = {"com.kaesar.spring"})
@EnableAsync // 开启异步调用
public class Application {public static void main(String[] args) {log.info("spring boot 开始启动...");
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
        String[] activeProfiles = ctx.getEnvironment().getActiveProfiles();
        for (String profile : activeProfiles) {log.info("以后环境为:" + profile);
        }
        log.info("spring boot 启动胜利...");
    }
}

示例一:根本应用形式

在办法上增加 @Async 注解

/**
 * 异步办法
 * 默认状况下,Spring 应用 SimpleAsyncTaskExecutor 去执行这些异步办法(此执行器没有限度线程数)。* 此默认值能够从两个层级进行笼罩:* 办法级别
 * 利用级别
 */
@Async
public void test2() {
    try {log.info(Thread.currentThread().getName() + "in test2, before sleep.");
        Thread.sleep(2000);
        log.info(Thread.currentThread().getName() + "in test2, after sleep.");
    } catch (InterruptedException e) {log.error("sleep error.");
    }
}

调用异步办法

/**
 * 调用不同类的异步办法
 */
public void func1() {log.info("before call async function.");
    asyncService.test2();
    log.info("after call async function.");
    try {Thread.sleep(3000);
    } catch (InterruptedException e) {log.error("sleep error.");
    }
    log.info("func end.");
}

执行后果

从执行后果能够看出,main 线程中的 func1 办法在调用异步办法 test2 后,没有期待 test2 办法执行实现,间接执行前面的代码。

示例二:在同一个类中调用异步办法

办法 func2 和下面的异步办法 test2 办法在同一个类中

从执行后果可知,main 线程中的 func2 办法在调用异步办法 test2 办法后,期待 test2 办法执行完后,才持续往后执行。

示例三:异步办法是 static 办法

异步办法 test3 是一个 static 办法

/**
 * 异步办法不能是 static 办法,不然注解生效
 */
@Async
public static void test3() {
  try {log.info(Thread.currentThread().getName() + "in test3, before sleep.");
    Thread.sleep(2000);
    log.info(Thread.currentThread().getName() + "in test3, after sleep.");
  } catch (InterruptedException e) {log.error("sleep error.");
  }

}

调用 test3 的办法

/**
 * 调用不同类的异步办法,异步办法是 static 办法
 */
public void func3() {log.info(Thread.currentThread().getName() + ": before call async function.");
  AsyncService.test3();
  log.info(Thread.currentThread().getName() + ": after call async function.");
  try {Thread.sleep(3000);
  } catch (InterruptedException e) {log.error("sleep error.");
  }
  log.info(Thread.currentThread().getName() + ": func end.");
}

执行后果。能够看出在 static 办法上增加 @Async 注解,当调用该办法时并没有新启用一个线程独自执行,而是按程序执行代码,阐明异步有效。

示例四:在办法级别上批改默认的执行器

自定义一个线程池执行器代替默认的执行器

自定义的线程池执行器

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

/**
 * 自定义线程池
 */
@Configuration
public class AsyncConfig {
    private static final int MAX_POOL_SIZE = 10;
    private static final int CORE_POOL_SIZE = 5;

    @Bean("asyncTaskExecutor")
    public AsyncTaskExecutor asyncTaskExecutor() {ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();
        asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        asyncTaskExecutor.setThreadNamePrefix("async-task-thread-pool-");
        asyncTaskExecutor.initialize();
        return asyncTaskExecutor;
    }
}

异步办法上应用自定义的执行器

/**
 * 在办法级别上批改默认的执行器
 */
@Async("asyncTaskExecutor")
public void test4() {
  try {log.info(Thread.currentThread().getName() + ": in test4, before sleep.");
    Thread.sleep(2000);
    log.info(Thread.currentThread().getName() + ": in test4, after sleep.");
  } catch (InterruptedException e) {log.error("sleep error.");
  }
}

调用 test4 异步办法

/**
 * 调用不同类的异步办法
 */
public void func4() {log.info(Thread.currentThread().getName() + ": before call async function.");
  asyncService.test4();
  log.info(Thread.currentThread().getName() + ": after call async function.");
  try {Thread.sleep(3000);
  } catch (InterruptedException e) {log.error("sleep error.");
  }
  log.info(Thread.currentThread().getName() + ": func end.");
}

从执行后果能够看出,@Async注解申明应用指定的自定义的异步执行器,曾经替换了默认的执行器。而且调用异步办法的 main 线程没有期待异步办法的执行。

阐明:新建自定义的执行器后,注解 @Async 默认就会替换成自定义的执行器,所以在 @Async 注解上能够不必指定。

$1.01^{365} ≈ 37.7834343329$
$0.99^{365} ≈ 0.02551796445$
置信保持的力量!

退出移动版