Spring對多線程支持

文章轉載至:https://blog.csdn.net/king_kgh/article/details/76022136

在我們的應用系統中,經常會處理一些耗時任務,自然而然的會想到使用多線程。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實現多線程是不是非常的簡單。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章