使用SpringBoot的@Async实现异步调用方法,以及自己开启新线程异步调用

2022-09-14 11:56:57 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

一. springboot的@Async注解实现异步

要在springboot中使用异步调用方法,只要在被调用的方法上面加上@Async就可以了

1.准备工作

准备一个springboot工程,在Application类上加上EnableAsync注解开启异步

代码语言:javascript复制
/** * @Author: zgd * @Date: 18/09/12 10:27 * @Description: */
@SpringBootApplication
@EnableAsync
public class Application { 
   

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

}

这个注解如果不加,@Async注解失效

2.controller

写一个同步接口和异步接口

代码语言:javascript复制
package com.zgd.demo.thread.asyn.controller;

import com.zgd.demo.thread.asyn.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Instant;

/** * @Author: zgd * @Date: 18/09/12 10:26 * @Description: hello */
@RestController
@RequestMapping("/hello")
public class HelloController { 
   

  @Autowired
  private HelloService helloService;

  /** * 异步方法 * @return */
  @RequestMapping("/asyn")
  public String getAsynHello(){ 
   
    long n = Instant.now().toEpochMilli();
    //异步
    String s = helloService.asynchSayHello();

    long f = Instant.now().toEpochMilli();
    return s   " 时间: "   (f-n);

  }

  /** * 同步方法 * * @return */
  @RequestMapping("/sync")
  public String getSyncHello(){ 
   

    long n = Instant.now().toEpochMilli();
    //异步
    String s = helloService.synchSayHello();

    long f = Instant.now().toEpochMilli();
    return s   " 时间: "   (f-n);
  }
}
3.helloService

写一个HelloService接口,并实现该接口

代码语言:javascript复制
package com.zgd.demo.thread.asyn.service.impl;

import com.zgd.demo.thread.asyn.service.HelloService;
import com.zgd.demo.thread.asyn.service.SleepService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/** * @Author: zgd * @Date: 18/09/12 10:43 * @Description: */
@Service
public class HelloServiceImpl implements HelloService { 
   

  @Autowired
  private SleepService sleepService;

  @Override
  public String synchSayHello() { 
   
    try { 
   
      sleepService.syncSleep();
      return "hello world,这是同步方法";
    } catch (InterruptedException e) { 
   
      e.printStackTrace();
      return "error";
    }
  }

  @Override
  public String asynchSayHello() { 
   
    try { 
   
      System.out.println("主线程 " Thread.currentThread().getName());
      sleepService.asyncSleep();
      return "hello world,这是异步方法";
    } catch (InterruptedException e) { 
   
      e.printStackTrace();
      return "error";
    }
  }
}

这里为了模拟应用场景,将耗时的方法放在另一个service里面,就叫SleepService,同样的,实现这个接口

代码语言:javascript复制
package com.zgd.demo.thread.asyn.service.impl;

import com.zgd.demo.thread.asyn.service.SleepService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/** * @Author: zgd * @Date: 18/09/12 10:46 * @Description: */
@Service
public class SleepServiceImpl implements SleepService { 
   

  @Override
  public void syncSleep() throws InterruptedException { 
   
    System.out.println("线程名: "  Thread.currentThread().getName());
    System.out.println("开始同步休眠3秒");
    Thread.sleep(3000);
    System.out.println("同步休眠结束");
  }

  @Override
  @Async
  public void asyncSleep() throws InterruptedException { 
   
    System.out.println("次线程 " Thread.currentThread().getName());

    System.out.println("开始异步休眠3秒");
    Thread.sleep(3000);
    System.out.println("异步休眠休眠结束");
  }
}

两个方法都是休眠3秒,aysncSleep方法上面有一个@Async注解

4.测试
  • 同步 访问 http://localhost:8080/hello/sync

控制台

要3秒的时间才能收到响应

  • 异步 访问 http://localhost:8080/hello/asyn

可见主线程和次线程打印出来的线程名不一样,也就是springboot帮我们开启了一个线程去处理

注意事项
  1. 必须要加@EnableAsync注解
  2. 不能在同一类下调用@Async注解的方法,比如A类下有a和b方法,b方法有@Async注解,不能直接这样a调用b,要把b放到其他类中
  3. @Async也可以打在类上,这样类下面的所有方法都是异步的(被其他类调用的时候)

二.开启线程实现异步

如果我们没有使用springboot,使用传统的方法怎么异步调用方法?还是开启一个新的线程

1.controller

增加一个接口

代码语言:javascript复制
/** * 同步方法 * * @return */
  @RequestMapping("/thread/asyn")
  public String getThreadSyncHello(){ 
   
    long n = Instant.now().toEpochMilli();
    //异步
    String s = helloService.threadAsynchSayHello();
    long f = Instant.now().toEpochMilli();
    return s   " 时间: "   (f-n);
  }
2.service

HelloServiceImpl

代码语言:javascript复制
@Override
  public String threadAsynchSayHello() { 
   
    //还是休眠3秒
    Runnable runnable = ()-> { 
   
      try { 
   
        sleepService.syncSleep();
      } catch (InterruptedException e) { 
   
        e.printStackTrace();
      }
    };
    System.out.println(Thread.currentThread().getName() " 开启新线程");
    new Thread(runnable).start();
    return "hello world,这是开启线程的异步方法";
  }
3.测试

我们访问 http://localhost:8080/hello/thread/asyn

同样的两个线程名不一样,开启了一个新线程处理,并且多次测试可以看出,自己直接开启线程比@Async要快几毫秒,不过可以忽略不计了

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157522.html原文链接:https://javaforall.cn

0 人点赞