BlameMe
BlameMe

Reputation: 71

Using Async multithreading in Spring to run concurrent tasks

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.

Upvotes: 1

Views: 1686

Answers (1)

Timur Levadny
Timur Levadny

Reputation: 530

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.

@Service
public Class1 {
...
@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:

@Async(...)
public Future<Object> method1() {
   ...
   return null;
}
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

Upvotes: 1

Related Questions