Do “nothing” while “condition”

2020-02-24 05:06发布

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?

5条回答
手持菜刀,她持情操
2楼-- · 2020-02-24 05:31

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        
}
查看更多
贼婆χ
3楼-- · 2020-02-24 05:31

You can easily make something like this with:

if(true){
 //Do nothing ...
}
查看更多
地球回转人心会变
4楼-- · 2020-02-24 05:33

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).
查看更多
smile是对你的礼貌
5楼-- · 2020-02-24 05:38

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).

查看更多
\"骚年 ilove
6楼-- · 2020-02-24 05:39

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.

查看更多
登录 后发表回答