在什么情况下可以做 - 虽然比在什么时候更有效?

时间:2013-05-08 10:00:05

标签: java performance while-loop do-while compare-and-swap

while vs. do-while

while和do-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操作,ForkJoinPool的javadoc解释:

  

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

由于他们承认这是不寻常的,我认为他们的意思是最好的而不是最简单的

问题

是否存在do {} while (!cas)效率高于while (!cas) {}且出于何种原因的情况?

3 个答案:

答案 0 :(得分:2)

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

简单演示

boolean condition = false;

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

输出"显示此文字"

正常

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

输出""

  • *由于条件错误而未显示任何输出。

为什么或在哪里使用,我没有满足需要,所以我无法帮助你。这只是一个确定问题/需求的问题,并使用您所知道的解决问题。类似于乐高 - 机械类不是'阻止'

答案 1 :(得分:0)

可能存在这样的情况:期望和更新的计算是复杂的,可以在调用compareAndSet的同一行中读取。 然后你可以在do:

中使它更具可读性
do {
  int expect = a.get();
  int update = expect + 1;
} while (!a.compareAndSet(expect, update));

答案 2 :(得分:0)

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

我已经问了一个非常类似的问题:compiling 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键运行。理论上,方法2更快,但在实践中它们应该是平等的。