文章轉載至: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實現多線程是不是非常的簡單。