在“条件”的同时做“无”

在浏览ForkJoinPool的Java 8版本的代码时(它从Java 7中有一些有趣的变化),我碰到了这个构造( 这里 ):

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

我正在努力为什么你会这样写而不是只是

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

它只是一个语义/可读性的select,因为你可以阅读第一个构造,因为do "nothing" while "conditions" ? 还是有一些额外的好处,我错过了?

如果你读到文件顶部的注释,就在类声明的下面,有一个部分解释了这个构造的使用:

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

ForkJoinPool大量使用了来自sun.misc.UnsafecompareAndSwap...以及ForkJoinPooldo {} while (...)大部分事件 – 正如其他答案所述 – 可以通过此注释在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. 

select使用do {} while (condition)来写一个while -loop的空主体似乎是一个主要的风格select。 这在HashMap可能更清楚了,它恰好在Java 8中进行了更新。

在Java 7的HashMap你可以find这个:

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

尽pipe其中的大部分代码也已经发生了变化,但Java 8中的replace显然是这样的:

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

第一个版本的缺点是,如果单独的分号恰好被删除,将会根据下面的行改变程序的含义。

如下所示,由while (...) {}do {} while (...);生成的字节码do {} while (...); 略有不同,但不以任何方式影响运行时的任何事情。

Java代码:

 class WhileTest { boolean condition; void waitWhile() { while(!condition); } void waitDoWhile() { do {} while(!condition); } } 

生成的代码:

 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 } 

撇开任何潜在的性能好处,都有明确的可读性好处。

while (X) ; 后面的分号乍一看并不总是显而易见的,您可能会觉得以下语句或语句是在循环内部的混淆。 例如:

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

将上面的内容误读为循环内部的if语句是非常容易的,即使你正确地读了它,也会很容易认为这是一个编程错误,如果应该在循环中。

do {} while(X); 尽pipe立即一目了然,没有任何机构的循环。

如果你会阅读上面的代码评论,提到的是…

如果调用者不是ForkJoinTask ,则此方法在行为上等同于

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

所以这只是在其他部分实现上面代码的另一种forms。

在Style的笔记中提到,

有一些不寻常的“do {} while(!cas …)”出现,这是强制更新CAS'edvariables的最简单的方法。

如果您将看到ManagedLocker#isReleasable的实现, 那么它正在更新锁,如果不需要阻塞,则返回true

解读:

空白while循环用于提供中断,直到某些条件重置为true / false。

在这里, do { } while(!...)是一个阻塞/中断,直到blocker.block()true时, blocker.isReleasable()将为true 。 循环将继续执行,而blocker不可释放( !blocker.isReleasable() )和封锁不被阻止! blocker.block()将被设置为true,执行将会失控。

请注意, do{ } while(...)不会更新CASvariables,但它确保程序将等待,直到variables得到更新(强制等待,直到variables得到更新)。

你可以很容易地做出这样的事情:

 if(true){ //Do nothing ... }