1

I am working on a spring boot project. I have a scenario where I need to make a service call, fetch data from DB and update a response object. I want to do these in two different threads in order to achieve better performance.

I tried using the following code

Thread t1 = new Thread(new Runnable(){

    public void run(){
        try {
            //make service call and update response object.
        }
        catch(Exception e){

        }
    }
    });

    t1.start();
    //fetch data from DB and update the response object.

    t1.join();

But this does not work when I try to hit the request and let it complete without putting any break points(basically executing it in the sequence that I want).

Is there a better alternative to achieve this?

Can I use fork and join here? If yes, how do I use it?

Please note that the data from service call and data from DB are not dependent on each other.

On further digging I found the below information in oracle documentation

http://www.oracle.com/technetwork/articles/java/fork-join-422606.html

First and foremost, fork/join tasks should operate as “pure” in-memory algorithms in which no I/O operations come into play. Also, communication between tasks through shared state should be avoided as much as possible, because that implies that locking might have to be performed. Ideally, tasks communicate only when one task forks another or when one task joins another.

Tushar Banne
  • 1,587
  • 4
  • 20
  • 38
  • can you please explain bit more "executing it in the sequence that I want" – Amit Bera Apr 10 '18 at 15:59
  • What I am doing is putting a breakpoint on the line where I am quering the DB and executing the new thread part at first. once the call is done and the response is updated, I release the thread on DB. – Tushar Banne Apr 10 '18 at 16:02
  • So, what I understood that you have created 2 thread one is T1 to make service call another T2 for fetch data from DB. Now you want T1 will execute first and complete its task after that T2 will start its task. Am I right? – Amit Bera Apr 10 '18 at 16:05
  • I want to execute both t1 and t2 simultaneously and wait for each other on completion. I did the above mentioned execution in order to check if the same object can be updated or not. – Tushar Banne Apr 10 '18 at 16:10
  • You could use an `Executor` to execute 2 `FutureTask`, the call to `get()` will be blocking. This should be the simplest solution, you could also check `CyclicBarrier`. – grape_mao Apr 10 '18 at 16:15
  • "wait for each other" doesn't make sense unless they _both_ have something else to do after they meet up. The code that you actually wrote is a more typical scenario: The main thread waits for the `t1` thread to do its job and die, and the `t1` thread doesn't wait for anything at all. – Solomon Slow Apr 10 '18 at 16:27
  • @jameslarge Then how do I make sure they wait for each other as sometimes the service call may be faster than DB call and vice versa. They both update the same response object but different fields. – Tushar Banne Apr 10 '18 at 16:37
  • A `CountDownLatch` with a count of 2 would be easiest probably. – Kayaman Apr 10 '18 at 16:42
  • Yes, I think CountDownLatch will be the solution. – Amit Bera Apr 10 '18 at 16:44
  • The `run()` method for your `t1` thread appears to make a service call, update a response object, and then it dies. At what point in that sequence do you want it to wait for the main thread? Why do you want it to wait at that point? – Solomon Slow Apr 10 '18 at 16:52
  • @jameslarge Understood my mistake. I was in perception that if t1 completes the execution, it will join with the main thread at t1.join(). Apparently that is not happening. As you pointed out, it is executing and dying. I wanted it to wait till the DB execution completes so that all the data can be sent at once in a single response object. Let me try CountDownLatch as suggested by Kayaman – Tushar Banne Apr 10 '18 at 17:04

3 Answers3

3

I think you do not need ForkJoinPool for that. You can use simply CountDownLatch. Main / parent thread will wait until the countdown to 0.

CountDownLatch latch = new CountDownLatch(2);
Thread t1 = new Thread(() -> {
    // do service call and update the response object 
    latch.countDown();
});
Thread t2 = new Thread(() -> {
    // do database call and update the response object 
    latch.countDown();
});

t1.start();
t2.start();

latch.await(); // main thread will wait here for the completion of T1 & T2 thread. 

Edited:

So handling the exception in a thread in a different way first way as below and it simple exception handling like we do.

Thread t1 = new Thread(() -> {
    // do service call
    try {
        // your code here
    } catch (Exception e) {

    }
    latch.countDown();
});

Another way is to use new Thread.UncaughtExceptionHandler() like below.

Thread.UncaughtExceptionHandler exceptionHandler = new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                //your exception handling code should come here
            }
        };

t1.setUncaughtExceptionHandler(exceptionHandler);

For more info about exception handling in Thread you can have a look on this

Amit Bera
  • 7,075
  • 1
  • 19
  • 42
1

What you need is a CompletableFuture here. While the other answers will definitely work, CompletableFutures compose very well. There's also full support for that in Spring Boot; so you can return an CompletableFuture from a controller.

You can definitely write that as follows:

return CompletableFuture.supplyAsync(() -> {
        // call service
        return service.doCall();
 }).thenComposeAsync(result -> {
        // update DB and return original result
        db.update(result);
        return result;
 });

thenComposeAsync() will make sure that the DB update will run after the service call.

By default, this expression will run on ForkJoinPool but you can define which ExecutorService they run on.

MuratOzkan
  • 2,599
  • 13
  • 25
0

Well first you go with the first example of the Doc you pass and saids::

Directly manipulating threads this way is fine for simple examples, but with concurrent programming, such code can quickly become error-prone, especially when several threads need to cooperate to perform a larger task. In such cases, their control flow needs to be coordinated.

So in the same Doc it suggest to use Executors:

Executors, which are an enhancement over plain old threads because they are abstracted from thread pool management. They execute tasks similar to those passed to threads (in fact, instances implementing java.lang.Runnable can be wrapped). Several implementations are provided with thread pooling and scheduling strategies. Also, execution results can be fetched both in a synchronous and asynchronous manner.

So change your simple Runnable thead to a Callable thread for getting a future variable and see how you can succes in that task:

The advantage of using Callable over Runnable is that Callable can explicitly return a value.

And check this answer for returning an Object for a Callabe

Gatusko
  • 2,503
  • 1
  • 17
  • 25