Spring对多线程支持

简介: Spring对多线程支持

在我们的应用系统中,经常会处理一些耗时任务,自然而然的会想到使用多线程。JDK给我们提供了非常方便的操作线程的API,JDK5之后更是新增了JUC包的支持,并发编程大师Doug Lea(JDK并发的作者)也是一直在为我们使用线程做着不懈的努力。

为什么还要使用Spring来实现多线程呢?这是句废话!实际有两个原因,第一使用Spring比使用JDK原生的并发API更简单。第二我们的应用环境一般都会集成Spring,我们的Bean也都交给Spring来进行管理,那么使用Spring来实现多线程更加简单,更加优雅。(更多的可能是在环境中就要这么用!!)

在Spring3之后,Spring引入了对多线程的支持,如果你使用的版本在3.1以前,应该还是需要通过传统的方式来实现多线程的。从Spring3同时也是新增了Java的配置方式,而且Java配置方式也逐渐成为主流的Spring的配置方式,因此后面的例子都是以Java的配置进行演示。

废话有点多,下面具体说说该如何在Spring中实现多线程,其实非常简单,只需要在配置类中添加@EnableAsync就可以使用多线程。在希望执行的并发方法中使用@Async就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线程池。下面举个例子来说明

首先定义配置类

如果对Java配置方式不了解的童鞋,可以参考这篇文章《初识SpringJava配置》

package com.hy.spring.test7;
 
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.hy.spring.test7")
@EnableAsync  // 启用异步任务
public class ThreadConfig  {
 
     // 这里是声明一个bean,类似于xml中的<bean>标签。
     // Executor 就是一个线程池
     @Bean
     public Executor getExecutor() {
          ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
          executor.setCorePoolSize(5);
          executor.setMaxPoolSize(10);
          executor.setQueueCapacity(25);
          executor.initialize();
          return executor;
     }
}

定义要执行的任务

package com.hy.spring.test7;
 
import java.util.Random;
import java.util.UUID;
 
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
 
@Service // 注解的方式把AsyncService交给Spring来管理
public class AsynTaskService {
 
     // 这里可以注入spring中管理的其他bean,这也是使用spring来实现多线程的一大优势
     
     @Async    // 这里进行标注为异步任务,在执行此方法的时候,会单独开启线程来执行
     public void f1() {
          System.out.println("f1 : " + Thread.currentThread().getName() + "   " + UUID.randomUUID().toString());
          try {
              Thread.sleep(new Random().nextInt(100));
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
     }
 
     @Async
     public void f2() {
          System.out.println("f2 : " + Thread.currentThread().getName() + "   " + UUID.randomUUID().toString());
          try {
              Thread.sleep(100);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
     }
}

测试类

package com.hy.spring.test7;
 
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
public class Main {
 
     public static void main(String[] args) {
          AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ThreadConfig.class);
          AsynTaskService service = context.getBean(AsynTaskService.class);
 
          for (int i = 0; i < 10; i++) {
              service.f1(); // 执行异步任务
              service.f2();
          }
          context.close();
     }
}

输出结果

f1 : ThreadPoolTaskExecutor-5   20e6ba88-ae51-42b9-aac6-ed399419fe6d
 
f2 : ThreadPoolTaskExecutor-2   0d7b1da4-e045-4d58-9054-e793f931cae1
 
f2 : ThreadPoolTaskExecutor-4   17b8d7c7-24e3-4bcf-b4da-822650a8f0be
 
f1 : ThreadPoolTaskExecutor-3   a9b32322-1c9b-4fc7-9c2a-1f7a81f2b089
 
f1 : ThreadPoolTaskExecutor-1   13a85fde-73c7-4c9b-9bb2-92405d1d3ac4
 
f2 : ThreadPoolTaskExecutor-3   8896caaf-381c-4fc3-ab0f-a42fcc25e5fd
 
f1 : ThreadPoolTaskExecutor-5   48246589-f8e9-4e9c-b017-8586bf14c0b0
 
f2 : ThreadPoolTaskExecutor-1   291b03ea-154f-46ba-bc41-69a61d1dd4d5
 
f1 : ThreadPoolTaskExecutor-4   856d8f48-70b4-475a-80cc-27d1635be36b
 
f2 : ThreadPoolTaskExecutor-2   1f7b1918-cf10-49a3-aaec-7b97a3a67e7d
 
f1 : ThreadPoolTaskExecutor-3   12e56d3f-d042-42dd-a387-3de80201c3b2
 
f2 : ThreadPoolTaskExecutor-5   bf0dbc97-61d8-4644-9ae4-4d711228198d
 
f1 : ThreadPoolTaskExecutor-3   4c58793a-394e-4241-87e6-fff1f480518d
 
f2 : ThreadPoolTaskExecutor-4   fa1d4484-d3a4-4303-9ffe-b6aaa791b157
 
f1 : ThreadPoolTaskExecutor-1   67144d54-d158-4c6a-865e-b80668515bea
 
f2 : ThreadPoolTaskExecutor-2   c48cfa18-48d4-4778-8f09-04b779338816
 
f1 : ThreadPoolTaskExecutor-3   30143849-3c49-4128-a811-f6468a091114
 
f2 : ThreadPoolTaskExecutor-5   58603271-ee4e-40c9-b6ff-199d32dfb02a
 
f1 : ThreadPoolTaskExecutor-1   3b0ce7ff-fdff-4e23-bb44-d1a0c1148982
 
f2 : ThreadPoolTaskExecutor-3   cb9a1543-955a-4bc9-b4e9-6b61188371ee
 

可以看到我们两个任务是异步进行的。

下面关于线程池的配置还有一种方式,就是直接实现AsyncConfigurer接口,重写getAsyncExecutor方法即可,代码如下

package com.hy.spring.test7;
 
import java.util.concurrent.Executor;
 
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
@Configuration
@ComponentScan("com.hy.spring.test7")
@EnableAsync
public class ThreadConfig implements AsyncConfigurer {
 
     @Override
     public Executor getAsyncExecutor() {
          ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
          executor.setCorePoolSize(5);
          executor.setMaxPoolSize(10);
          executor.setQueueCapacity(25);
          executor.initialize();
          return executor;
     }
 
     @Override
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
          return null;
     }
 
}

使用Spring实现多线程是不是非常的简单。

相关文章
|
6月前
|
人工智能 JSON 前端开发
【Spring boot实战】Springboot+对话ai模型整体框架+高并发线程机制处理优化+提示词工程效果展示(按照框架自己修改可对接市面上百分之99的模型)
【Spring boot实战】Springboot+对话ai模型整体框架+高并发线程机制处理优化+提示词工程效果展示(按照框架自己修改可对接市面上百分之99的模型)
|
6月前
|
Java 关系型数据库 数据库连接
BATJ高频面试249道题:微服务+多线程+分布式+MyBatis +Spring
本文收集整理了各大厂常见面试题N道,你想要的这里都有内容涵盖:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等技术栈,希望大家都能找到适合自己的公司,开开心心的撸代码。
|
2月前
|
Java Spring
spring多线程实现+合理设置最大线程数和核心线程数
本文介绍了手动设置线程池时的最大线程数和核心线程数配置方法,建议根据CPU核数及程序类型(CPU密集型或IO密集型)来合理设定。对于IO密集型,核心线程数设为CPU核数的两倍;CPU密集型则设为CPU核数加一。此外,还讨论了`maxPoolSize`、`keepAliveTime`、`allowCoreThreadTimeout`和`queueCapacity`等参数的设置策略,以确保线程池高效稳定运行。
240 10
spring多线程实现+合理设置最大线程数和核心线程数
|
6月前
|
安全 Java Spring
Spring框架中的单例Bean是线程安全的吗?
Spring框架中的单例Bean是线程安全的吗?
81 1
|
4月前
|
Java Spring
spring boot 中默认最大线程连接数,线程池数配置查看
spring boot 中默认最大线程连接数,线程池数配置查看
311 4
|
4月前
|
Java Spring 容器
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
204 3
|
3月前
|
安全 Java C#
Spring创建的单例对象,存在线程安全问题吗?
Spring框架提供了多种Bean作用域,包括单例(Singleton)、原型(Prototype)、请求(Request)、会话(Session)、全局会话(GlobalSession)等。单例是默认作用域,保证每个Spring容器中只有一个Bean实例;原型作用域则每次请求都会创建一个新的Bean实例;请求和会话作用域分别与HTTP请求和会话绑定,在Web应用中有效。 单例Bean在多线程环境中可能面临线程安全问题,Spring容器虽然确保Bean的创建过程是线程安全的,但Bean的使用安全性需开发者自行保证。保持Bean无状态是最简单的线程安全策略;
|
4月前
|
安全 Java 数据库连接
Spring Boot 优雅关机时异步线程安全优化
Spring Boot 优雅关机时异步线程安全优化
113 1
|
4月前
|
Java BI 调度
在Spring Boot中实现多线程任务调度
在Spring Boot中实现多线程任务调度
|
5月前
|
监控 安全 Java
Spring Boot优雅Shutdown时异步线程安全优化
Spring Boot优雅Shutdown时异步线程安全优化