8

while 与 do-while

当块为空时, while 和 do-while 在功能上是等效的,尽管 while 看起来更自然:

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

带有空块的 while/do-while 的一个典型用例是使用 compareAndSet (CAS) 强制更新原子对象。例如,下面的代码将以a线程安全的方式递增:

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

语境

java.util.concurrent 的几个部分使用do {} while (...)CAS 操作的习语和解释的 javadoc ForkJoinPool

有几次出现异常do {} while (!cas...),这是强制更新 CAS 变量的最简单方法。

既然他们承认这很不寻常,我想他们的意思是best而不是simple

问题

do {} while (!cas)有没有比这更有效的情况while (!cas) {}?出于什么原因?

4

3 回答 3

2

所以'do while'意味着它将在while循环中运行一次代码。然后,如果条件为真,它只会在 while 循环内运行代码。

简单演示

boolean condition = false;

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

输出“此文本显示”

普通的

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

输出 ””

  • *由于条件为假,没有显示输出。

为什么或在哪里使用 do while,我没有遇到需要,所以我无法帮助你。这只是识别问题/需求,并使用你所知道的来解决它的问题。类似于乐高 - 机械类型而不是“块”。

于 2014-10-09T15:38:58.883 回答
0

在某些情况下,expect 和 update 的计算非常复杂,以至于在调用 compareAndSet 的同一行中可读。然后你可以让它在 do 中更具可读性:

do {
  int expect = a.get();
  int update = expect + 1;
} while (!a.compareAndSet(expect, update));
于 2013-05-08T10:12:35.570 回答
0

这不是效率问题。有些情况没有 do{}while() 就无法解决。看看 java.util.Random.next(int bits)。如果您尝试对 while(){} 执行相同操作,则会出现代码重复,因为循环体必须在条件之前执行一次。

我已经问过一个非常类似的问题:compile loops in Java

这段代码:

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);
    }
}

被编译成:

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

您可能会注意到 method1() 中第 13 行的附加指令。但正如我的问题中的回答所建议的那样,当由 JIT 编译成机器指令时,这没有任何区别。非常难以捉摸的性能改进。任何证明它的方法都必须使用 PrintAssembly 键运行。理论上method2更快,但在实践中它们应该是相等的。

于 2013-05-08T11:00:56.177 回答