欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot笔记—多线程系列(一)—使用多线程

程序员文章站 2022-05-01 13:04:29
...

1 使用场景

​ 在Spring Boot项目中,有时候需要单独监控某一个业务,或者需要在主流程之外单独处理一些数据。

​ 在Spring项目中,由于Bean 对象是spring容器管理的,直接new出来的对象是没法使用bean里面依赖的其他组件,如dao,mapper等。此时,如果想使用bean里依赖的其他组件,则需要spring的多线程。

此篇文章,只是介绍了使用spring多线程的简单方式。至于多线程的参数设置,自定义线程池等将在另外的文章详解。

2 实现方式

2.1 使用Spring封装的异步

2.1.1 介绍

Spring Boot开启异步,需要两个注解:@EnableAsync和@Async。

  • @EnableAsync

    在配置类中通过添加该注解,开启对异步任务的支持。

  • @Async

    在实际执行的bean的方法中使用该注解表名这是一个异步任务。

2.1.2 样例

2.1.2.1 目录结构

Study
├── src
│   ├── main
│   │   ├── java
│   │   │   └── top
│   │   │       └── yxdz
│   │   │           └── study
│   │   │               ├── StudyApplication.java
│   │   │               └── spring
│   │   │                   └── springboot
│   │   │                       └── thread
│   │   │                           └── service
│   │   │                               ├── ITestService.java
│   │   │                               └── impl
│   │   │                                   └── TestSerivceImpl.java
│   └── test
│       └── java
│           └── top
│               └── yxdz
│                   └── study
│                       └── StudyApplicationTests.java

2.1.2.2 代码

  • StudyApplicationTests——测试入口

    这是测试类,也是配置类,添加了注解@EnableAsync,用来在此测试中启用异步。

    package top.yxdz.study;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.test.context.junit4.SpringRunner;
    import top.yxdz.study.spring.springboot.thread.service.ITestService;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @EnableAsync
    public class StudyApplicationTests {
    
        @Autowired
        ITestService iTestService;
    
        @Test
        public void contextLoads() {
    
            for(int i=0; i<5; i++){
                iTestService.method1("Async" + i);
            }
    
            try {
                //等待10s,防止异步代码被强制关闭导致线程抛出异常
                Thread.sleep(10000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
  • ITestService——测试类接口

    package top.yxdz.study.spring.springboot.thread.service;
    
    public interface ITestService {
    
        /**
         * 异步测试
         * @param msg
         */
        void method1(String msg);
    }
  • TestSerivceImpl——测试类实现

    这是实现类,在实现函数上添加了注释@Async表示异步调用。

    import org.slf4j.LoggerFactory;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    import top.yxdz.study.spring.springboot.thread.service.ITestService;
    
    import java.time.LocalDateTime;
    
    
    @Service("TestSerivceImpl")
    public class TestSerivceImpl implements ITestService {
    
        private static Logger LOG = LoggerFactory.getLogger(TestSerivceImpl.class);
    
        @Override
        @Async
        public void method1(String msg){
    
            try {
                LOG.info(LocalDateTime.now().toString() + msg);
                Thread.sleep(1000);
                LOG.info(LocalDateTime.now().toString() + msg);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

2.1.2.3 执行结果

  • 执行结果

    2018-12-12 20:07:37.631  INFO 34428 --- [         task-5] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:37.631Async4
    2018-12-12 20:07:37.631  INFO 34428 --- [         task-1] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:37.631Async0
    2018-12-12 20:07:37.631  INFO 34428 --- [         task-4] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:37.631Async3
    2018-12-12 20:07:37.631  INFO 34428 --- [         task-2] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:37.631Async1
    2018-12-12 20:07:37.631  INFO 34428 --- [         task-3] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:37.631Async2
    2018-12-12 20:07:38.635  INFO 34428 --- [         task-4] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:38.635Async3
    2018-12-12 20:07:38.635  INFO 34428 --- [         task-2] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:38.635Async1
    2018-12-12 20:07:38.635  INFO 34428 --- [         task-3] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:38.635Async2
    2018-12-12 20:07:38.635  INFO 34428 --- [         task-1] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:38.635Async0
    2018-12-12 20:07:38.635  INFO 34428 --- [         task-5] t.y.s.s.s.t.s.impl.TestSerivceImpl       : 2018-12-12T20:07:38.635Async4
  • 结果说明

    该方式使用的是异步,执行iTestService.method1("Async" + i);时,会开一个线程执行,并不会影响主线程的运行,for循环会毫无障碍(不会受Thread.sleep(1000)的影响)运行完毕,同时也会产生四个线程,独立运行method1方法。

    因为是四个线程独立运行的结果,所以结果的顺序并不能保证每次一致。