当前位置: 首页 > news >正文

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

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

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

 

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

进入正题:

先上个目录结构:

好了,我们这次是在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);
    }
}

 

好了,跑一下:

结合代码看看,懂了吧应该。  

稍微解释一哈:

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

asyncTestService.function2();

 

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

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

这结果是我们想要的。

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

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

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

 

 

好了,就到这吧。

 

相关文章:

  • Springboot中 使用request的几种方法。
  • 使用WebStorm 报错解决方法!!Unable to save settings: Failed to save settings (内含注册码破解码)
  • Angular7 关于Bootstrap4.x.x版本无法使用Glyphicons 字体图标 简单解决方案
  • springboot 获取访问接口的请求的IP地址
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • 什么是Kafka
  • Springboot 线程同步之Semaphore 的简单使用
  • JAVA Gson的使用
  • JAVA 最全最细的fastjson使用介绍,带你透彻领悟JSON
  • fastJson注解@JSONField 的作用及其效果
  • HttpClient 不同版本的超时时间设置
  • 使用两个栈实现队列,简单例子
  • 数据库ACID
  • 线程小记
  • JAVA JDK1.8 时间戳与时间格式化 实用工具类
  • [ JavaScript ] 数据结构与算法 —— 链表
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • Angular2开发踩坑系列-生产环境编译
  • canvas绘制圆角头像
  • export和import的用法总结
  • JAVA_NIO系列——Channel和Buffer详解
  • Javascripit类型转换比较那点事儿,双等号(==)
  • JavaScript学习总结——原型
  • LeetCode算法系列_0891_子序列宽度之和
  • Map集合、散列表、红黑树介绍
  • MYSQL 的 IF 函数
  • rc-form之最单纯情况
  • Solarized Scheme
  • STAR法则
  • Twitter赢在开放,三年创造奇迹
  • 程序员该如何有效的找工作?
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 基于Vue2全家桶的移动端AppDEMO实现
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 试着探索高并发下的系统架构面貌
  • 我的面试准备过程--容器(更新中)
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • #Z2294. 打印树的直径
  • #控制台大学课堂点名问题_课堂随机点名
  • $.ajax()
  • (C)一些题4
  • (C语言)字符分类函数
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (黑马C++)L06 重载与继承
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (转)Scala的“=”符号简介
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .MSSQLSERVER 导入导出 命令集--堪称经典,值得借鉴!
  • .NET BackgroundWorker
  • /etc/X11/xorg.conf 文件被误改后进不了图形化界面
  • /var/lib/dpkg/lock 锁定问题
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [Android 数据通信] android cmwap接入点