英文:
Using Async multithreading in Spring to run concurrent tasks
问题
我对Spring非常新,我正在尝试从两个单独的类中调用两个方法,多次调用每个方法,并且我希望每次调用都会启动一个新线程,以便它们并发运行。这是我编写的代码:
主类:
@SpringBootApplication
@EnableOAuth2Client
@EnableAsync
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
class SomeOtherClass {
for (int i = 0; i < 100; i++) {
Class1 class1 = new Class1();
class1.method1(//它的参数);
}
// 做其他事情
// ...
// 方法2将使用方法1的副作用,因此理想情况下,下一个for循环应该在前一个for循环结束后才开始
for (int i = 0; i < 50; i++) {
Class2 class2 = new Class2();
class2.method2(//它的参数);
}
}
public Class1 {
@Async("threadPoolTaskExecutor")
public void method1() throws Exception {
LOGGER.info("在{}中运行此方法", Thread.currentThread().getName());
}
}
public Class2 {
@Async("threadPoolTaskExecutor")
public void method2() throws Exception {
LOGGER.info("在{}中运行此方法", Thread.currentThread().getName());
}
}
@Configuration
@EnableAsync
public class ThreadConfig {
@Bean("threadPoolTaskExecutor")
public TaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(100);
executor.setMaxPoolSize(100);
executor.initialize();
return executor;
}
}
问题是当我运行应用程序时,我只看到一个线程名称打印,这意味着它并未以多线程方式运行。从日志中可以看出,调用是按顺序进行的。通过使用标准Java(Runnable)进行多线程处理,我知道多线程版本应该更快完成。由于我对Spring非常陌生,我不明白我做错了什么。
我已经删除了方法名称和逻辑,但注释和类结构完全相同,因此如果您发现任何问题,请指出。
<details>
<summary>英文:</summary>
I am very new to Spring and I am trying to call two methods from two separate classes a number of times, and I want each invocation to spin a new thread so they run concurrently. This is the code I have:
the main class:
@SpringBootApplication
@EnableOAuth2Client
@EnableAsync
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
class SomeOtherClass {
for (int i = 0; i < 100; i++) {
Class1 class1 = new Class1();
class1.method1(//its arguments);
}
// doing other things
// ...
// method 2 will use the side effects of method 1, so ideally this next
// for loop should start only after the previous one is over
for (int i = 0; i < 50; i++) {
Class2 class2 = new Class2();
class2.method2(//its arguments);
}
}
public Class1 {
@Async("threadPoolTaskExecutor")
public void method1() throws Exception {
LOGGER.info("Running this in {}", Thread.currentThread().getName());
}
}
public Class2 {
@Async("threadPoolTaskExecutor")
public void method2() throws Exception {
LOGGER.info("Running this in {}", Thread.currentThread().getName());
}
}
@Configuration
@EnableAsync
public class ThreadConfig {
@Bean("threadPoolTaskExecutor")
public TaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(100);
executor.setMaxPoolSize(100);
executor.initialize();
return executor;
}
}
The problem is when I run the application I only see one thread name printing, which means it's not running in a multithreaded way. Looking at the logs, I can also see the calls are being made sequentially. Having done multithreading using standard Java (Runnable), I know the multithreaded version should finish much faster. Since I am very new to Spring, I do not understand what I am doing wrong.
I have redacted the method names and logic, but the annotations and class structures are exactly thee same, so if you see any problem with that please point that out.
</details>
# 答案1
**得分**: 1
要使 `method1` 和 `method2` 异步工作,您需要让 Spring 管理 Class1 和 Class2 的实例。将 `Class1 class1 = new Class1();` 替换为依赖注入。
```java
@Service
public Class1 {
...
```
```java
@Service
class SomeOtherClass {
@Autowired
Class1 class1;
//...
// 您的循环
```
编辑:
如果您需要在第一个循环中的所有异步执行完成后才执行第二个循环,您可以使用 `Future` 类:
```java
@Async(...)
public Future<Object> method1() {
...
return null;
}
```
```java
List<Future<Object>> futures = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
futures.add(class1.method1(/*其参数*/));
}
futures.forEach(f -> {
try {
f.get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
});
// 所有 method1 的调用已完成
```
<details>
<summary>英文:</summary>
To get `method1` and `method2` work asynchronously you have to let Spring manage instances of the Class1 and Class2. Replace `Class1 class1 = new Class1();` with the dependency injection.
```java
@Service
public Class1 {
...
```
```java
@Service
class SomeOtherClass {
@Autowired
Class1 class1;
//...
// your loops
```
EDIT:
If you need to perform second loop only after completion of all async executions in the first loop then you can use `Future` class:
```java
@Async(...)
public Future<Object> method1() {
...
return null;
}
```
```java
List<Future<Object>> futures = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
futures.add(class1.method1(/*its arguments*/));
}
futures.forEach(f -> {
try {
f.get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
});
// all of invocations of method1 are finished
```
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论