0

Here is a scenario, when the output I am expecting from below code is
First Function
Second Function
Main Execution Completed!

But the problem here is the run method that prints "Second Function" is never getting the value of volatile flag to true to print "Second Function" and call countDown on countdownlatch object. Hence the countdownlatch.await() keeps waiting without any outcome. Is there any other approach to execute the respective run methods in a particular sequence? I understand this defeats the purpose of asynchronous programming in java, but if at all its possible kindly let me know.

public class Application {
    private static CountDownLatch countDownLatch = new CountDownLatch(2);

    public static void executeAndWait(List<Runnable> runnables) {
        runnables.forEach(r -> new Thread(r).start());
    }

    public static void main(String[] args) throws InterruptedException  {
        List<Runnable> runnables = Arrays.asList(() -> {
            try {
                while(flag) {
                    Thread.sleep(100);
                    System.out.println("Second Function");
                    countDownLatch.countDown();
                    break;
                }
            } catch(Exception e) {}
        }, () -> {
            try {
                Thread.sleep(100);
                System.out.println("First Function");
                flag = true;
                countDownLatch.countDown();
            } catch(Exception e) {}
        });
        executeAndWait(runnables);
        countDownLatch.await();
        System.out.println("Main Execution Completed!");
    }
} 
  • `while (flag)` will most probably not be entered since `flag` starts out being `false`. – Turing85 Jul 21 '23 at 14:33
  • @Turing85 - so at some point the run that prints "First Function" will make that volatile flag to true, so should it not enter the while loop then? and if this doen't work whats the alternative approach? I tried using AtomicBoolean -- same result. – Curious Coder Jul 21 '23 at 14:35
  • The code is incomplete. Please [edit] the post and add all relevant information, in particular the initialization of `countDownLatch` and `flag`. – Turing85 Jul 21 '23 at 14:35
  • 1
    "*... so should it not enter the while loop then?*" - This is not how `while` loops work. I recommend reading a tutorial about `while` loops, e.g. [this one over at `docs.oracle.com`](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/while.html). – Turing85 Jul 21 '23 at 14:37
  • @Turing85 look above the code, its there along with the class name. – Curious Coder Jul 21 '23 at 14:37
  • Oh. Didn't see that due to the faulty format... – Turing85 Jul 21 '23 at 14:38
  • Definition of `flag` is missing though. I am going to assume it is defined at `static volatile boolean flag = false;`. – Turing85 Jul 21 '23 at 14:39
  • @Turing85 kindly let me know if there is an alternate approach. – Curious Coder Jul 21 '23 at 14:39

1 Answers1

1

Core problem here is that when the second thread reaches the condition guarding the while loop:

...
while(flag) {
...

flag may be either true of false. If flag is false then the whole loop is skipped, and the execution of that thread terminates.

What we actually want is an endless loop, with a condition that

  • prints some text,
  • decreases the latch, and
  • breaks out of the loop

when flag is true.

Hence, we can rewrite the Runnable:

() -> {
  try {
    while (true) { // keep looping...
      if (flag) { // ... until flag is set 
        System.out.println("Second Function");
        countDownLatch.countDown();
        break;
      }
      Thread.sleep(100);
    }
  } catch (Exception e) {
  }
}

ideone.com demo


A remark on the code: We can and should move the try { ... } catch (...) { ... } as close to the Thread.sleep(...) as possible. Hence, I propose the following structual change:

() -> {
  while (true) {
    try {
      Thread.sleep(100);
    } catch (Exception e) {
    }
    if (flag) {
      countDownLatch.countDown();
      System.out.println("Second Function");
      break;
    }
  }
}
Turing85
  • 18,217
  • 7
  • 33
  • 58
  • It worked. Thanks a lot! – Curious Coder Jul 21 '23 at 14:55
  • @CuriousCoder, Turing85 said, "...`flag` may be either `true` or `false`." FYI, that is called a "race condition." One thread races to set the flag. The other thread races to examine it. The outcome of the program is unpredictable. It depends on which thread wins the race. That's not, in and of itself, a bad thing, but it can be a bad thing if, as in your case, one of the possible outcomes is not an _acceptable_ outcome. – Solomon Slow Jul 22 '23 at 00:16