SpringBoot 最简单的使用异步线程案例 @Async

简介: SpringBoot 最简单的使用异步线程案例 @Async

在网上找了很多很多资料,使用多线程、异步线程等等,很多配置,方法也多多;


那么,我向来都是以简单,够用为目标,下面我介绍的就是我认为已经非常非常简单的异步线程使用的方法了。

 

说到简单,当然是使用注解。


进入正题:


先上个目录结构:


image.png


好了,我们这次是在springboot里面使用的,不用导啥包。


我们先创个异步线程的配置类, 我的叫ThreadConfig,你们随意:


package com.async.config;
import java.util.concurrent.Executor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@ComponentScan("com.async.service")
@EnableAsync
public class ThreadConfig  {
    /**
     * 执行需要依赖线程池,这里就来配置一个线程池
     * @return
     */
    // 当池子大小小于corePoolSize,就新建线程,并处理请求
    // 当池子大小等于corePoolSize,把请求放入workQueue(QueueCapacity)中,池子里的空闲线程就去workQueue中取任务并处理
    // 当workQueue放不下任务时,就新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做拒绝处理
    // 当池子的线程数大于corePoolSize时,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁
   @Bean("getExecutor")
    public Executor getExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心线程数
        executor.setCorePoolSize(10);
        //设置最大线程数
        executor.setMaxPoolSize(100);
        //线程池所使用的缓冲队列
        executor.setQueueCapacity(250);
        //设置线程名
        executor.setThreadNamePrefix("JcTest-Async");
        //设置多余线程等待的时间,单位:秒
        //executor.setKeepAliveSeconds();
        // 初始化线程
        executor.initialize();
        return executor;
    }
}


向来我都不做代码过多的解释,因为我的代码注释 已!经!足!够!详!细 ! 了!

不过还是得提一下这俩注解,


@ComponentScan("com.async.service") 这个是告诉全世界,我即将开启异步线程的业务方法是哪个


@EnableAsync 这个! 必须有!  告诉全世界允许我使用异步线程


好了,接下来我们创建一下业务层的东西吧:


AsyncTestService:


package com.async.service;
public interface AsyncTestService {
    /**
     * 这里将会在impl里标注为异步任务,在执行此方法的时候,会单独开启线程来执行
     */
   void function1() throws InterruptedException;
    void function2();
}


AsyncTestServiceImpl:


package com.async.service.impl;
import com.async.service.AsyncTestService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
public class AsyncTestServiceImpl implements AsyncTestService {
    /**
     * 这里进行标注为异步任务,在执行此方法的时候,会单独开启线程来执行
     */
    @Async("getExecutor")
    public void function1() throws InterruptedException {
        System.out.println("f1 : " + Thread.currentThread().getName() + "   " + UUID.randomUUID().toString());
//        try {
//            Thread.sleep(10000);
//            System.out.println("EEEE");
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        //故意等10秒,那么异步线程开起来,这样明显看到 2方法不用等1方法执行完再调用了
        Thread.sleep(10000);
        System.out.println("EEEE");
    }
    @Async("getExecutor")
    public void function2() {
        System.out.println("f2 : " + Thread.currentThread().getName() + "   " + UUID.randomUUID().toString());
        try {
            Thread.sleep(100);
            System.out.println("aaaa");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


代码不走读了,但是必须得提下注解:


@Async这个是告诉全世界,这里! 只要被调用,就是会开启一个异步线程。

至于后面加上("getExecutor"),是为了指定读取自己写的配置信息例如线程名称那些。

 

最后是TestController:


package com.async.test;
import com.async.service.AsyncTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
    @Autowired
    AsyncTestService asyncTestService;
    @GetMapping("/test")
    public void test() throws InterruptedException {
//        for (int i = 0; i < 10; i++) {
//            asyncTestService.function1(); // 执行异步任务
//            asyncTestService.function2();
//        }
        asyncTestService.function1(); // 执行异步任务
        asyncTestService.function2();
    }
}


启动类没啥改变:


package com.async;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class, args);
    }
}


好了,跑一下:


image.png结合


代码看看,懂了吧应该。  


稍微解释一哈:


asyncTestService.function1(); // 执行异步任务


asyncTestService.function2();


本来按照正常,肯定是按顺序执行的,也就是先编译完方法1,输出所有东东,再到方法2;


然后我们配了异步,而且在方法1那边sleep了蛮久的, 所以你看到输出结果,显然方法2自己单飞了,并没有等方法1;


这结果是我们想要的。


最后提醒一下, 有没有发现,我这个例子分了好多层,而且连impl都分了的。其实不分那么细也没问题,但是!!!


有个需要注意的!  利用@Async注解的方法, 不能跟调用它的方法放在同个类里面!!!! 否则会循环依赖错误!!!


还有一个需要注意的,@Async所修饰的函数不要定义为static类型,这样异步调用不会生效!


好了,就到这吧。


相关文章
|
1天前
|
监控 Java Spring
Spring Boot中一般如何使用线程池?
在Spring Boot应用程序中,合理地使用线程池可以有效地提高系统的性能和并发处理能力。本文将深入探讨Spring Boot中如何一般性地使用线程池,包括线程池的配置、使用方式以及一些最佳实践。
24 0
|
1天前
|
Java
线程安全问题-卖票案例实现
线程安全问题-卖票案例实现
11 0
|
1天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
11 0
|
1天前
|
数据采集 Web App开发 Java
Python 爬虫:Spring Boot 反爬虫的成功案例
Python 爬虫:Spring Boot 反爬虫的成功案例
|
1天前
|
监控 Java API
Spring Boot与异步任务:整合与应用场景
【4月更文挑战第29天】异步任务在现代应用程序开发中扮演着重要的角色,它们可以提高应用程序的性能和响应速度,尤其适用于处理长时间运行的任务或需要等待外部资源的场景。Spring Boot提供了强大的支持来简化异步任务的实现。
26 0
|
1天前
|
自然语言处理 Java 索引
SpringBoot 实现 elasticsearch 查询操作(RestHighLevelClient 的案例实战)
SpringBoot 实现 elasticsearch 查询操作(RestHighLevelClient 的案例实战)
25 1
|
1天前
|
SQL Dubbo Java
案例分析|线程池相关故障梳理&总结
本文作者梳理和分享了线程池类的故障,分别从故障视角和技术视角两个角度来分析总结,故障视角可以看到现象和教训,而技术视角可以透过现象看到本质更进一步可以看看如何避免。
84037 99
案例分析|线程池相关故障梳理&总结
|
1天前
|
JSON Java Maven
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
45 0
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
|
1天前
|
XML 前端开发 JavaScript
SpringBoot之响应案例的详细解析
SpringBoot之响应案例的详细解析
13 0
|
1天前
|
Java API 调度
springboot的异步类的介绍
【4月更文挑战第18天】FutureTask 是 Java 并发 API 中的一个实用类,它实现了 Future 接口并扩展了 Runnable,因此它可以被 ExecutorService 执行。FutureTask 通常用于包装 Callable 或 Runnable 对象,这样它们就可以提交给 ExecutorService 并获得 Future 对象,用于查询计算的状态和结果
15 1