Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant way to run parallel threads in Spring 4


I am developing an API. This API needs to do 2 DB queries to get the result.
I tried following strategies:

  • Used callable as return type in Controller.
  • Created 2 threads in Service (use Callable and CoundownLatch) to run 2 queries parallel and detect finishing time.

    public class PetService {
        public Object getData() {
            CountDownLatch latch = new CountDownLatch(2);
            AsyncQueryDBTask<Integer> firstQuery= new AsyncQueryDBTask<>(latch);
            AsyncQueryDBTask<Integer> secondQuery= new AsyncQueryDBTask<>(latch);
            latch.await();
    }
    
    public class AsyncQueryDBTask<T> implements Callable {
    
       private CountDownLatch latch;
    
       public AsyncQueryDBTask(CountDownLatch latch) { this.latch = latch;}
    
       @Override
       public T call() throws Exception {
        //Run query
        latch.countDown();
       }
    

It worked fine but I feel that I am breaking the structure of Spring somewhere.

I wonder what is the most efficient way to get data in Spring 4.
-How to know both of 2 threads that run own query completed their job?
-How to control thread resource such as use and release thread?

Thanks in advance.

like image 636
duy Avatar asked Feb 06 '23 04:02

duy


1 Answers

You generally don't want to create your own threads in an ApplicationServer nor manage thread lifecycles. In application servers, you can submit tasks to an ExecutorService to pool background worker threads.

Conveniently, Spring has the @Async annotation that handles all of that for you. In your example, you would create 2 async methods that return a Future :

public class PetService {
    public Object getData() {
        Future<Integer> futureFirstResult = runFirstQuery();
        Future<Integer> futureSecondResult = runSecondQuery();

        Integer firstResult = futureFirstResult.get();
        Integer secondResult = futureSecondResult.get();
    }

    @Async
    public Future<Integer> runFirstQuery() {
        //do query
        return new AsyncResult<>(result);
    }

    @Async
    public Future<Integer> runSecondQuery() {
        //do query
        return new AsyncResult<>(result);
    }
}

As long as you configure a ThreadPoolTaskExecutor and enable async methods, Spring will handle submitting the tasks for you.

NOTE: The get() method blocks the current thread until a result is returned by the worker thread but doesn't block other worker threads. It's generally advisable to put a timeout to prevent blocking forever.

like image 196
Laplie Anderson Avatar answered Feb 07 '23 19:02

Laplie Anderson