在“条件”的同时做“无”
在浏览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.Unsafe
的compareAndSwap...
以及ForkJoinPool
中do {} 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 ... }