1

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.

1
  • 1
    In your SomeOtherClass you should use Spring Bean of Class1 and Class2 not just new a object of them. Commented Oct 19, 2020 at 0:53

1 Answer 1

1

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 
Sign up to request clarification or add additional context in comments.

3 Comments

How can I make sure the first loop is completely done before the second loop even begins (even if it blocks the flow it must happen)?
How would this have to change for a method that returns void? This code is not working and I get a nullpointerexception
You have to set Future as a return type to be able to wait for the end of execution. If your method has the void return type then it's safe to replace by Future and just return null. Where are you getting NPE?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.