70

While browsing the code for the Java 8 version of ForkJoinPool(which has a few interesting changes from Java 7) I ran across this construct (here):

do {} while (!blocker.isReleasable() &&
             !blocker.block());

I'm struggling with why you would write it like this instead of just

while (!blocker.isReleasable() &&
       !blocker.block());

Is it just a semantics/readability choice, since you could read the first construct as do "nothing" while "conditions"? Or is there some additional benefit I'm missing?

Erik Vesteraas
  • 4,675
  • 2
  • 24
  • 37

5 Answers5

54

If you read the comments at top of the file, just below the class declaration, there is a section which explains the use of this construct:

Style notes

===========

[...]

There are several occurrences of the unusual "do {} while
(!cas...)"  which is the simplest way to force an update of a
CAS'ed variable. There are also other coding oddities (including
several unnecessary-looking hoisted null checks) that help
some methods perform reasonably even when interpreted (not
compiled).
Graham Borland
  • 60,055
  • 21
  • 138
  • 179
MicSim
  • 26,265
  • 16
  • 90
  • 133
  • 25
    Since I needed a reminder myself: CAS is http://en.wikipedia.org/wiki/Compare-and-swap – Erik Vesteraas Jul 07 '14 at 12:02
  • 14
    You may have explained how the construct helps "to force an update of a CAS'ed variable". – Honza Zidek Jul 07 '14 at 19:16
  • 7
    But why is it causing an update of a CAS'ed variable unlike the `while` version? – Benjamin Gruenbaum Jul 08 '14 at 05:56
  • Unfortunately I don't have the required knowledge to answer this question, but maybe the comment "simplest way to force an update" doesn't refer to the two versions (do-while vs. while), but rather to the way of updating a CAS'ed variable using an empty block in a while loop. That means that both (do-while **and** while) would update the CAS'ed variable. Read this question for reference: [In what situations can do-while be more efficient than while?](http://stackoverflow.com/q/16437751/44522). – MicSim Jul 08 '14 at 07:52
  • 4
    It doesn't say whether do {} while (condition) vs. while (condition) do ; makes any difference. If it makes a difference, then this is (a) an awful bad comment, (b) I consider it a _bug_ not having the comment at the statement itself, and (c) the fact that it makes a difference is a major WTF in the language. – gnasher729 Jul 08 '14 at 09:16
  • @glglgl, this question is not about C, it's about Java too. – xaizek Jul 08 '14 at 21:13
  • @xaizek Oups. Must have been half asleep :-O – glglgl Jul 09 '14 at 06:59
  • 3
    This sounds like deep magic where the scope change `do {} while()` avoids a JIT optimization that the `while()` uses. The while statements are semantically equivalent so the difference must be in the implementation of the JVM. – Michael Shopsin Jul 09 '14 at 16:32
  • 1
    The "Style Notes" don't say anything about why one version was chosen over the other. It only explains why a `while` loop was used **at all**. I think that the reasons are rather those in the [answer by Erik Vesteraas](http://stackoverflow.com/a/24613352/3182664), namely 1. Clarity and **readability (!)**, and 2. Smaller bytecode (1 byte is 1 byte). – Marco13 May 19 '16 at 13:26
45

ForkJoinPool makes extensive use of compareAndSwap... from sun.misc.Unsafe and most of the occurrences of do {} while (...) in ForkJoinPool can — as mentioned by other answers — be explained by this comment under the heading Style notes:

* There are several occurrences of the unusual "do {} while
* (!cas...)"  which is the simplest way to force an update of a
* CAS'ed variable. 

The choice to use write a while-loop with an empty body as do {} while (condition) seems however to be a mostly stylistic choice. This is perhaps clearer in HashMap, which happened to be updated in Java 8.

In the Java 7 HashMap you can find this:

while (index < t.length && (next = t[index++]) == null)
    ;

While much of the code around it has also changed, it is clear that the replacement in Java 8 is this:

do {} while (index < t.length && (next = t[index++]) == null);

The first version has the weakness that if the lone semicolon happened to be deleted it would change the meaning of the program depending on the following line.

As seen below, bytecode generated by while (...) {} and do {} while (...); is slightly different, but not in any way that should affect anything when run.

Java code:

class WhileTest {
    boolean condition;

    void waitWhile() {
        while(!condition);
    }

    void waitDoWhile() {
        do {} while(!condition);
    }
}

Generated code:

class WhileTest {
  boolean condition;

  WhileTest();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  void waitWhile();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field condition:Z
       4: ifne          10
       7: goto          0
      10: return        

  void waitDoWhile();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field condition:Z
       4: ifeq          0
       7: return        
}
Erik Vesteraas
  • 4,675
  • 2
  • 24
  • 37
  • 3
    Coming here from a [duplicate question](http://stackoverflow.com/questions/37323549/weird-loops-used-in-spliterator-of-java-8) : This IMHO is a far better and more convincing answer than the currently accepted one. – Marco13 May 19 '16 at 13:21
8

Leaving aside any potential performance benefits, there is a clear readability benefit.

With while (X) ; the trailing semicolon is not always obvious at first glance, you may be confused into thinking that the following statement or statements are inside the loop. For example:

while (x==process(y));
if (z=x) {
    // do stuff.
}

It would be very easy to misread the above as having the if statement inside the loop, and even if you did read it correctly it would be easy to think that it was a programming mistake and the if should be inside the loop.

With do {} while(X); though it is immediately at a glance clear that there is no body to the loop.

Tim B
  • 40,716
  • 16
  • 83
  • 128
  • Why not simply write `while (x==process(y)) {}`? I think that would be almost as clear as the `do ... while()` solution. – exilit Jul 11 '14 at 10:36
  • @exilit that would help but because the `do {} while` construction has keywords inbetween the brackets it makes the separation cleaner. Even in that simple example we already have 4 brackets after each other `)){}` - you can easily see that that number could increase as the if grows more complicated...so it's easier to just not notice the `{}` in with all the others. – Tim B Jul 11 '14 at 10:45
4

If you will read comment above the code, It is mentioned that...

If the caller is not a ForkJoinTask, this method is behaviorally equivalent to

while (!blocker.isReleasable())
   if (blocker.block())
      return;
}

So it is just another form to implement above code in else part...!!

In Style notes it is mentioned that,

There are several occurrences of the unusual "do {} while (!cas...)" which is the simplest way to force an update of a CAS'ed variable.

And if you will see implementation of ManagedLocker#isReleasable, It is updating the lock and returns true if blocking is unnecessary.

Interpretation :

Blank while loops are used to provide an interrupt until some condition reset to true/false.

Here, do { } while(!...) is a blocker/interrupt until blocker.block() will be true when blocker.isReleasable() is false. Loop will continue execution while blocker is not releasable (!blocker.isReleasable()) and blocker is not blocked !! Execution will be out of loop as soon as blocker.block() will set to true.

Note that, do{ } while(...) does not update CAS variable, but it guarantee that program will wait until variable gets updated (force to wait until variable gets updated).

Not a bug
  • 4,286
  • 2
  • 40
  • 80
  • Yes, but the do {} while (condition) construct is used in both cases. So the comment is indeed just a third way to write the same thing. – Erik Vesteraas Jul 07 '14 at 11:48
  • @ErikVesteraas updated the answer, It was in progress when you commented :D – Not a bug Jul 07 '14 at 11:59
  • So is the comment in the style notes implying that `while(!cas...)` would not force an update? That there is an actual technical difference as shown by the bytecode? I'm beginning to wonder if looking at isReleasable is a distraction, as there are many places where it is used for actual CAS-variables like this: `do {} while (!U.compareAndSwapLong(...));` – Erik Vesteraas Jul 07 '14 at 12:51
  • @ErikVesteraas I dont think `isReleasable()` is a distraction, See the interpretation edit. – Not a bug Jul 07 '14 at 13:04
  • 2
    Yes, I agree with what you have written, but it does not address whether `while(!cas...);` would be able to force an update on a CompareAndSwap-variable, or if `do {} while (!cas...);` is necessary, i.e. whether there is an actual technical difference or not. – Erik Vesteraas Jul 07 '14 at 13:22
  • @ErikVesteraas I think it can not force to update variable, but it can force program to wait until variable will be updated. – Not a bug Jul 07 '14 at 13:29
  • @KisHanSarsecHaGajjar Can you please explain more clearly what the difference in the actual byte code is between the two constructs? How does the `do{}` enable this interrupt? – Dawood ibn Kareem Jul 07 '14 at 19:23
  • @DavidWallace It is not like only `do{}while(...)` enables interrupt, it can be done with `while() { }` also. and for byte code, You can refer Erik's answer, in this pattern additional `goto` is not required because of `ifeq` instruction is there instead of `ifne`... I never said only `do{}` are used to enable interrupt !! ;) :D – Not a bug Jul 08 '14 at 05:12
  • @KisHanSarsecHaGajjar - as Erik Vesteraas has shown the byte code in his answer, I cannot see any support for the "way to force an update of a CAS'ed variable" statement. There is virtually no difference between `while(...);` and `do{}while(...);` in the byte code. Only one unconditional jump less. – Honza Zidek Jul 08 '14 at 07:10
  • You forgot the word "simplest...", and for more you can read my answer again, I think it describes the logic. – Not a bug Jul 08 '14 at 07:13
0

You can easily make something like this with:

if(true){
 //Do nothing ...
}
larsaars
  • 2,065
  • 3
  • 21
  • 32