8

I have a question about Spring's @Async annotation and how to correctly use it. Let's say I have these methods:

@Async
public void test(String param1) {
    test2(param1, null);
}

@Async
public void test2(String param1, String param2) {
    test3(param1, param2, null);
}

@Async
public void test3(String param1, String param2, String param3) {
    // do some heavy work
}

Do I need to have @Async on all three methods for it to be called asynchronously or is it enough only to have it on test3 that will actually do the work?

kryger
  • 12,906
  • 8
  • 44
  • 65
Vedran Kopanja
  • 1,259
  • 12
  • 23

3 Answers3

4

You do need it only at one method. Just because, after a new thread is started with the first @Async-method, is is asynchronous to the invoking method.

But what this mean for you, is highly depending on what your example should illustrate:

1) So in your case, an @Async for test1(String param1) is enough when you ever invoke test2 and test3 through test1.

@Async
public void test1(String param1) {
    test2(param1, null);
}

private void test2(String param1, String param2) {
    test3(param1, param2, null);
}

private void test3(String param1, String param2, String param3) {
    // do something
}

note that the methods 2 and 3 are private


2) But if your example is for illustrating a method overloading pattern for default parameters (Method chaining), then it is more complicate. Then you would need to have the @Async annotation at the method that do the real stuff. Because you just want to execute the real execution in an async-way, but not one async invocation for each chaining step.

public void test(String param1) {
    test(param1, null);
}


public void test(String param1, String param2) {
    //this invocation runs async only when real AspectJ is used
    test(param1, param2, null);
}

@Async
public void test(String param1, String param2, String param3) {
    // do something
}

note that all methods are named just test (method chaining pattern)

The problem with this is, that Spring (without real AspectJ load- or compile-time weaving) will not run a method async if it is invoked via this! (see https://stackoverflow.com/a/22561903/280244)

Community
  • 1
  • 1
Ralph
  • 118,862
  • 56
  • 287
  • 383
  • Yes, they are overloaded methods actually, don't know why I called them test1, test2 and test3 here... So basically, the method that does some async work (``test3`` in this case), must be public for it to actually be asynchronous (since I'm not using AspectJ)? Others shouldn't bother with the annotation? – Vedran Kopanja Nov 30 '15 at 09:44
2

I think @Ralph covered your concerns.

But as the name of the question is "How to use @Async correctly in Spring", I have to mention this:

You should always change (or at least consider to change) default task executor in Spring context or use custom task executor.

Because:

By default, a SimpleAsyncTaskExecutor will be used to process async method invocations.

and:

NOTE: This implementation does not reuse threads! Consider a thread-pooling TaskExecutor implementation instead, in particular for executing a large number of short-lived tasks.

luboskrnac
  • 23,973
  • 10
  • 81
  • 92
0

Using @Async only on the third method test3 is not enough because calling locally cause that object is not proxied and only proxied objects (picked up from container, e.g. using @Autowired) has async calls

Also look here

Community
  • 1
  • 1
k0ner
  • 1,086
  • 7
  • 20