8

While vs. do-while

While and do-while are functionally equivalent when the blocks are empty, although while seems more natural:

do {} while (keepLooping());
while (keepLooping()) {}

One typical use case of a while/do-while with an empty block is to force an update of atomic objects with a compareAndSet (CAS). For example the code below will increment a in a thread-safe way:

int i;
AtomicInteger a = new AtomicInteger();
while (!a.compareAndSet(i = a.get(), i + 1)) {}

Context

Several parts of java.util.concurrent use the do {} while (...) idiom for CAS operations and the javadoc of ForkJoinPool explains:

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

Since they admit it is unusual, I suppose they meant best rather than simplest.

Question

Are there situations where do {} while (!cas) can be more efficient than while (!cas) {} and for what reasons?

assylias
  • 321,522
  • 82
  • 660
  • 783
  • Maybe it's just historical preference. Anyway, why use `{}` at all---`while (condition);` is what I'd write. – Marko Topolnik May 08 '13 at 10:24
  • 1
    @MarkoTopolnik Agreed on the `;`. I found [this video](http://emergingtech.chariotsolutions.com/2013/04/phillyete-screencast-7-doug-lea-engineering-concurrent-library-components/), where Doug Lea says around minute 57:00: "*Don't use while, use do-while, because of safepoints*", and the slide mentions "smaller race window". I suppose he refers to GC safepoints although I don't see how it makes a difference here. – assylias May 08 '13 at 10:41
  • 1
    Doug's being quite elliptical about this :) The best way I can interpret it is not about do-while vs. while, but about using the loop body for assignment vs. cramming everything into the condition. – Marko Topolnik May 08 '13 at 10:56
  • @MarkoTopolnik That's what I understand too - but then why the trouble? I guess SO is not the best place to ask! – assylias May 08 '13 at 10:59
  • 3
    Yeah... it's "not constructive" for SO because only about three people on Earth can give an answer that ascends beyond speculation :) – Marko Topolnik May 08 '13 at 11:03
  • `do/while` loops can be useful when your code must iterate the loop at least once and/or when your loop initializes a variable checked inside the `while` condition. – Shadow Man May 30 '13 at 01:09
  • Other reasons why it is "not constructive" are that 1) the answer most likely depends on the version of Java you are using, and 2) even if there is a difference, it is unlikely to be significant in the vast majority of cases. – Stephen C Oct 09 '14 at 15:59

3 Answers3

2

So a 'do while' means it will run the code in the while loop once. Then, it only runs the code inside the while loop if the condition is true.

Simple demonstration

boolean condition = false;

do{
  System.out.Println("this text displayed");
}while(condition == true);

Output "this text displayed"

Normal

while(condition == true){
 System.out.Println("this text displayed");
}

output ""

  • *no output displayed due to condition being false.

Why or where you would use do while, I havn't come accross the need to so I can't help you there. It's just a matter of identifying a problem/need, and using what you know to solve it.similar to lego-the mechanical kind not 'blocks'.

kyle england
  • 118
  • 10
0

There might have been situations where the calculation of expect and update is to complex to be readable in same line as you call compareAndSet. Then you may make it more readable inside a do:

do {
  int expect = a.get();
  int update = expect + 1;
} while (!a.compareAndSet(expect, update));
oe.elvik
  • 507
  • 2
  • 10
  • The question assumes empty blocks so that while & do-while are strictly equivalent. – assylias May 08 '13 at 10:14
  • Aha. Maby this is more like it – oe.elvik May 08 '13 at 10:44
  • See this for a real example: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/concurrent/ForkJoinPool.java#ForkJoinPool.postBlock%28%29 - I don't think this is the issue. – assylias May 08 '13 at 10:46
  • In most cases i agree that while (cas); is better. I only show the example of a situations where do {} while (!cas) can be more readable than while (!cas) {}. This is maby why the do {} while is more common in documentation – oe.elvik May 08 '13 at 10:50
  • Your code won't compile since `expect` and `update` is out of scope as soon as you leave the loop body. Declaring the two variables before the loop would work though, so your point is still valid. – siegi Jul 11 '14 at 20:39
0

This is not a question of efficiency. Some cases just can't be solved without do{}while(). Have look at java.util.Random.next(int bits). If you try to do the same with while(){} you'd have a code duplicate, because cycle body have to be executed once before condition.

I've asked a very similar question already: compiling loops in Java.

This code:

public class Test {

    static int i = 0;

    public static void main(String[] args) {
        method1();
        method2();
    }

    public static void method2() {
        do{}while(++i < 5);
    }

    public static void method1() {
        while(++i < 5);
    }
}

is compiled into:

public static void method2();
  Code:
   0:   getstatic       #4; //Field i:I
   3:   iconst_1
   4:   iadd
   5:   dup
   6:   putstatic       #4; //Field i:I
   9:   iconst_5
   10:  if_icmplt       0
   13:  return

public static void method1();
  Code:
   0:   getstatic       #4; //Field i:I
   3:   iconst_1
   4:   iadd
   5:   dup
   6:   putstatic       #4; //Field i:I
   9:   iconst_5
   10:  if_icmpge       16
   13:  goto    0
   16:  return

You might notice additional instruction on line 13 in method1(). But as was suggested by answer in my question, this does not have any difference when compiled by JIT into machine instructions. Very elusive performance improvement. Any way to prove it you have to run with PrintAssembly key. In theory method2 is faster, but in practice they should be equal.

Community
  • 1
  • 1
Mikhail
  • 4,175
  • 15
  • 31
  • 2
    You haven't read the question carefully enough. There is no loop body at all and the question of efficiency is very low-level, concerning eventual native code ordering. – Marko Topolnik May 08 '13 at 11:02
  • I've just had a look at the assembly and nothing strikes me. – assylias May 08 '13 at 14:31
  • What do you mean? Is it all the same? – Mikhail May 08 '13 at 17:46
  • Only two instructions appear in a different order, rest is strictly identical. – assylias May 08 '13 at 21:24
  • These are not doing, what you think they are doing. `method1 iterates four times, method2 iterates once`. So this result is quite normal and you are comparing wrong things – smttsp May 30 '13 at 06:16
  • In this case loop body is empty, so it does not make sense. Condition is the point. – Mikhail May 30 '13 at 06:30
  • 1
    Why do people think that disassembled bytecodes are instructive? 1) We all *know* what `while` and `do while` mean. 2) You cannot deduce anything about code efficiency from bytecodes. The JIT compiler is where the significant optimization happens. (Even methods with identical bytecode sequences could perform differently ... due to the way that the JIT compiler uses runtime stats from the interpreter.) – Stephen C Oct 09 '14 at 15:54