首页后端开发其他后端知识Java异步调用与同步调用是什么,用法是怎样

Java异步调用与同步调用是什么,用法是怎样

时间2024-03-25 02:14:03发布访客分类其他后端知识浏览1498
导读:在这篇文章中我们将学习“Java异步调用与同步调用是什么,用法是怎样”的相关知识,下文有详细的介绍及实例,步骤过程清晰,简单易懂,小编觉得挺不错的,有需要的朋友可以借鉴参考,希望大家阅读完这篇能有所获。...
在这篇文章中我们将学习“Java异步调用与同步调用是什么,用法是怎样”的相关知识,下文有详细的介绍及实例,步骤过程清晰,简单易懂,小编觉得挺不错的,有需要的朋友可以借鉴参考,希望大家阅读完这篇能有所获。

异步调用与同步调用
  • 同步调用:顺序执行,通过调用返回结果再次执行下一个调用
  • 异步调用:通过调用,无需等待返回结果,执行下一个调用

1. @Async讲解

其@Async的注解代码如下:

@Target({
ElementType.TYPE, ElementType.METHOD}
)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
    
    String value() default "";

}

注解可以使用在类型以及方法中
通过value定义其值,默认是空

一般这个注解需要配合@EnableAsync,起源码如下

@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 Integer.MAX_VALUE;

}

主要通过该注解放置在启动类中进行配置启动

在启动类中添加如下:

@SpringbootApplication
@EnableAsync
public class Application{

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

    }

}

2. 用法

2.1 同步调用

从调用到返回函数结果才能执行下一步,称为同步调用

service层 代码:

public class Service{

    public void test01() throws InterruptedException{
    
        Thread.sleep(5000);
    
        System.out.println("保存日志");

    }

}

控制层代码模块:

public class Controler{
    
 @Autowired
 private Service service;


 @GetMapping("/test")
 public String getTest(){

  try{
    
   System.out.println("开始");
    
   service.test01();
    
   System.out.println("结束");
   
  }
catch(InterruptedException e){
    
   e.prinStackTrace();

  }

 }

 
}

通过springboot的启动类启动之后

输出如下:

开始

// 此为等待5秒钟,终端不显示也不关闭

结束

2.2 异步调用

异步调用,执行函数不用等返回结果就可以执行下一步

service层 代码:
主要是添加了@Async注解标识这个方法

public class Service{

    @Async
    public void test01() throws InterruptedException{
    
        Thread.sleep(500);
    
        System.out.println("保存日志");

    }

}

控制层代码模块:

通过调用service层函数

public class Controler{
    
 @Autowired
 private Service service;


 @GetMapping("/test")
 public String getTest(){

  try{
    
   System.out.println("开始");
    
   service.test01();
    
   System.out.println("结束");
   
  }
catch(InterruptedException e){
    
   e.prinStackTrace();

  }

 }

 
}

以及在启动类中加入注解启动 @EnableAsync

@SpringbootApplication
@EnableAsync
public class Application{

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

    }

}
    

3. 自定义线程池

对于线程池的一些基本知识可看我之前的文章:

java如何正确关闭线程以及线程池(代码实践含源码分析)
java线程池的创建方式详细分析(全)

如果不指定线程池,默认使用的线程池为SimpleAsyncTaskExecutor(来一个任务就创建一个线程,不断创建线程导致CPU过高引发OOM),自带的线程池一般都有弊端,一般推荐使用ThreadPoolExecutor(明确线程池的资源,规避风险)

具体如下:

  • newFixedThreadPool:定死了线程数,任务队列还是无界的,(最大线程数只有队列满了,最大线程数才会创建),所以会造成OOM
  • newCachedThreadPool:没有设置最大线程数上限,创建大量的线程容易卡顿或者直接OOM

通过自定义线程池可以调整线程池的配置,更好的资源利用

@Async这个注解查找 AsyncConfigurer接口(实现类为AsyncConfigurerSupport,默认配置和方法都是空),所以可重写接口指定线程池。

  • 通过实现接口AsyncConfigurer
  • 继承AsyncConfigurerSupport
  • 自定义TaskExecutor(替代内置任务执行器)

第三种方法:

在application.xml中定义线程池的一些变量

thread.core.size=16
thread.max.size=16
thread.queue.size=30

thread.prefix=xx-

自定义线程池如下

import org.springframework.beans.factory.annotation.Value;
    
import org.springframework.context.annotation.Bean;
    
import org.springframework.context.annotation.Configuration;
    
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    

import java.util.concurrent.ThreadPoolExecutor;


@Configuration
public class ThreadPoolConfig {

 // 线程名称前缀
  @Value("${
thread.prefix}
    ")
  private String threadPrefix;

 
 // 核心线程数
  @Value("${
thread.core.size}
    ")
  private int coreSize;


 // 最大线程数
  @Value("${
thread.max.size}
    ")
  private int maxSize;

 
 // 队列长度
  @Value("${
thread.queue.size}
    ")
  private int queueSize;

 
 // 通过bean注解注入
  @Bean("xx")
  public ThreadPoolTaskExecutor taskExecutor() {
    
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    
    //设置线程池参数信息
    taskExecutor.setCorePoolSize(coreSize);
    
    taskExecutor.setMaxPoolSize(maxSize);
    
    taskExecutor.setQueueCapacity(queueSize);
    
    taskExecutor.setThreadNamePrefix(threadPrefix);
    
    taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
    
    taskExecutor.setAwaitTerminationSeconds(30);
    
   
    //修改拒绝策略为使用当前线程执行
    taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    
   
    //初始化线程池
    taskExecutor.initialize();
    
    return taskExecutor;

  }

}
    

感谢各位的阅读,以上就是“Java异步调用与同步调用是什么,用法是怎样”的内容了,通过以上内容的阐述,相信大家对Java异步调用与同步调用是什么,用法是怎样已经有了进一步的了解,如果想要了解更多相关的内容,欢迎关注网络,网络将为大家推送更多相关知识点的文章。

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: Java异步调用与同步调用是什么,用法是怎样
本文地址: https://pptw.com/jishu/652472.html
PHP中静态化包括什么,怎么理解 PHP中实现修改数组的方法有哪些

游客 回复需填写必要信息