Springboot中使用多线程

本文介绍如何在SpringBoot中使用@Async注解实现多线程,并解决使用@Bean创建对象导致的循环依赖问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

Spring boot中使用多线程的方式有很多种,最简单的方式就是使用@Async注解来实现。本文重点讲解多线程的使用和使用多线程注解出现循环依赖的的问题及解决方案。

一.在SpringBoot的启动类开启多线程


必须添加@EnableAsync注解,来开启对多线程的支持,否则@Async注解无效。

在启动类中创建出对象,调用方法,即会创建两个线程来执行各自的方法了。

@SpringBootApplication
@EnableAsync
public class MyApplication {
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
        TestReceiver t1 = context.getBean(TestReceiver.class);
        TestReceiver2 t2 = context.getBean(TestReceiver2.class);
        t1.hello();
        t2.hello();
    }

二.@Async注解创建线程


直接在方法上加上@Async注解,该方法会创建一个线程来执行。

package com.test.receiver;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class TestReceiver {

    @Autowired
    @Lazy
    private Map<String, Object> consumerConfigs;

    private static final Logger log = LoggerFactory.getLogger(TestReceiver.class);

    @Async
    public void hello() {
        while (true) {
            log.info("***************1111111111*******************");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在创建一个类,两个类中各有一个方法用子线程运行:

package com.test.receiver;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class TestReceiver2 {

    @Autowired
    private Map<String, Object> consumerConfigs;

    private static final Logger log = LoggerFactory.getLogger(TestReceiver2.class);

    @Async
    public void hello() {
        while (true) {
            log.info("************22222222*******************");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

这样就可以运行了,启动后即可同时异步执行这两个方法了。

三.遇到的循环依赖问题及解决


1.错误描述

在实际使用的时候,发现并没有如此顺利。
上面的TestReceiver类,由于都注入了一个consumerConfigs(此行代码:private Map<String, Object> consumerConfigs;)

在启动的时候,就会报错:

org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'testReceiver': Unsatisfied dependency expressed through field 'consumerConfigs'; 
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
Error creating bean with name 'testReceiver2': 
Bean with name 'testReceiver2' has been injected into other beans [testReceiver]
in its raw version as part of a circular reference, but has eventually been wrapped. 
This means that said other beans do not use the final version of the bean. 
This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.

错误提示consumerConfigs已经在testReceiver2中注入了,出现了循环注入。

2.问题定位

consumerConfigs这个Bean的创建代码:

@Bean(name = "consumerConfigs")
    public Map<String, Object> consumerProps() {
        Map<String, Object> props = new HashMap<>();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServer);
        return props;
    }

发现在多个类中引用@Service@Component注入的Bean没有问题,但是多处引用@Bean注入的对象,却出现了循环引用的错误。

3.解决方案:

第二个类中,注入consumerConfigs的时候,加上注解@Lazy,配合@Autowired 一起使用,完整安全注入示例:

    @Autowired
    @Lazy
    private Map<String, Object> consumerConfigs;

再次启动,循环依赖问题成功解决。

总结


Spring boot中使用多线程注解@Async注解要配合@EnableAsync一起使用,但在需要在多处引用由@Bean声明创建的对象时候,在引用处,需要用注解@Lazy配合@Autowired来注入,来防止出现循环依赖的问题。

Spring Boot中使用多线程可以使用Java多线程编程的相关类和接口,例如`Thread`、`Runnable`和`Executor`等,并且可以通过Spring的依赖注入特性来管理线程池。 下面是一个示例代码: ```java import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component public class MultiThreadService { @Async // 声明这个方法是一个异步方法,Spring会自动创建一个线程池来执行这个方法 public void doTask1() { // 具体操作 System.out.println("Task 1 is running on thread " + Thread.currentThread().getName()); } @Async public void doTask2() { // 具体操作 System.out.println("Task 2 is running on thread " + Thread.currentThread().getName()); } } ``` 在以上示例中,我们在Spring Boot中定义了一个`MultiThreadService`类,其中定义了两个异步方法`doTask1`和`doTask2`。在这两个方法上添加了`@Async`注解,表示这两个方法是异步执行的。 接下来,在Spring Boot的配置类中添加`@EnableAsync`注解,启用异步方法。示例代码如下: ```java import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; @Configuration @EnableAsync // 启用异步方法 public class AsyncConfig { } ``` 最后,在Spring Boot的控制器中调用`MultiThreadService`的异步方法即可。示例代码如下: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MultiThreadController { @Autowired private MultiThreadService multiThreadService; @GetMapping("/test") public String test() { multiThreadService.doTask1(); multiThreadService.doTask2(); return "Success"; } } ``` 以上代码中,我们在控制器中调用了`MultiThreadService`的异步方法`doTask1`和`doTask2`,Spring会自动创建一个线程池来执行这两个方法。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值