0

I have a problem. I have 4 classes: classA, classB, classC with all a function called run(). Now I am trying to work with async, so what I want is the following:

  1. In my MainClass, I call a async function from classA called run()
  2. At the end of classA.run(), I call a classB.run()
  3. In my MainClass, I want to wait until classA and classB have printed their line before running classC.run().

Here is the code from every class. Class A:

public class classA {

    public void run() {

        System.out.println("CLASS A");

        new classB().run();

    }
    
}

Class B:

public class classB {
    
    public void run() {

        System.out.println("CLASS B");

    }

}

Class C:

public class classC {

    public void run() {

        System.out.println("CLASS C");

    }
    
}

And here is the code from my MainClass:

public class MainClass {

    public static void main(String[] args) {

        CompletableFuture<Void> testRun = CompletableFuture.runAsync(() -> {
            new classA().run();
        });

        CompletableFuture<Void> test2Run = CompletableFuture.completedFuture(testRun).thenRunAsync(() -> {
            new classC().run();
        });

    }

}

But in my terminal I don't see any prints...

What am I doing wrong?

A. Vreeswijk
  • 822
  • 1
  • 19
  • 57
  • I added full code, but it's not much, because I created a quick test project. The result of this program is no print in the command line, but for what I could understand is that prints that are executed async do get printed? – A. Vreeswijk May 02 '21 at 10:12

2 Answers2

1

There are two issues with your code:

  1. You are not waiting for the completion of your tasks. They run in async to your main() method, but they might not finish in time before the main() method do. This means you might not see the output from your tasks, depending if they were fast enough or not (see "race condition"). Use get() or join() to wait for the completion.
  2. CompletableFuture.completedFuture() is not used to "wait" for another task to finish. You are building two tasks which run in parallel, which can results in output like "A, C, B". If you want to "wait" for completion, you use something like CompletableFuture.allOf() or CompletableFuture.anyOf(), depending on what you need.
Progman
  • 16,827
  • 6
  • 33
  • 48
  • Yess!!! This did the trick. Just a little side question which is kinda related to this. My main program closes when the tasks are finished, but what if I open an API stream in a task... Then I want the program to never finish, but keep running? Where should I look for on google? – A. Vreeswijk May 02 '21 at 10:49
  • @A.Vreeswijk If you want your application prevent from terminating, create a non-deamon thread. See other questions like https://stackoverflow.com/questions/7416018/when-does-the-main-thread-stop-in-java/7416103#7416103 – Progman May 02 '21 at 10:52
  • Thanks, I will take a look into it! :) – A. Vreeswijk May 02 '21 at 10:54
1

testRun and testRun2 are executed by threads in ForkJoinPool.commonPool().
Threads in ForkJoinPool.commonPool() terminate upon main thread's termination.

To wait for the asynchronous actions to complete, you should invoke awaitTermination.

So, the main method should look like:

public class MainClass {

    public static void main(String[] args) {
        CompletableFuture<Void> testRun = CompletableFuture.runAsync(() -> {
            new classA().run();
        });

        CompletableFuture<Void> test2Run = CompletableFuture.completedFuture(testRun).thenRunAsync(() -> {
            new classC().run();
        });

       ForkJoinPool.commonPool().awaitTermination(10, TimeUnit.SECONDS);
   }
}

Edit: A cleaner way to wait for all tasks to complete is:

CompletableFuture.allOf(testRun, test2Run).join();
adarsh
  • 1,393
  • 1
  • 8
  • 16