for(;;)和while(true)的区别

简介: for(;;)和while(true)的区别

问题来源

在阅读Java的JDK源码时,发现大部分写源码的大佬多采用for(;;)的方式来死循环,比如说AQS(AbstractQueuedSynchronizer)中大量使用的自旋的方式获取共享状态。

/**

* 通过“死循环”的方式来正确的添加节点

*/

private Node enq(final Node node) {

   // 不断循环,直至CAS插入节点成功

   for (;;) {

       Node t = tail;

       if (t == null) {

           // 当尾节点为null,此时需要初始化头节点和尾节点

           if (compareAndSetHead(new Node()))

               tail = head;

       } else {

           // 插入节点前驱节点指向原先尾节点

           node.prev = t;

           // CAS插入至同步队列的尾节点

           if (compareAndSetTail(t, node)) {

               t.next = node;

               return t;

           }

       }

   }

}

/**

* “死循环”获取同步状态,并且当前仅当前驱节点是头节点是才能够尝试获取同步状态

*/

final boolean acquireQueued(final Node node, int arg) {

   boolean failed = true;

   try {

       boolean interrupted = false;

       // 不断循环

       for (;;) {

           // 获取当前节点的前驱节点,如果前驱节点为null将会抛出空指针异常

           final Node p = node.predecessor();

           // 如果当前节点的前驱节点是头节点,尝试获取同步状态

           if (p == head && tryAcquire(arg)) {

               // 设置当前节点为头节点,并且将节点线程和节点的前驱节点置为null,help GC

               setHead(node);

               p.next = null; // help GC

               failed = false;

               return interrupted;

           }

           // 如果不符合条件,则判断当前节点前驱节点的waitStatus状态来决定是否需要挂起LockSupport.park(this);

           if (shouldParkAfterFailedAcquire(p, node) &&

               parkAndCheckInterrupt())

               interrupted = true;

       }

   } finally {

       // 失败则取消

       if (failed)

           cancelAcquire(node);

   }

}


比较

Java代码在编译后都会装换为虚拟机可以识别的字节码,我们通过编译器对两者生成的字节码从原理是来观察两者的区别

测试代码for

package com.liziba.jsw;


/**

* <p>

*  for死循环测试

* </p>

*

* @Author: Liziba

* @Date: 2021/6/21 11:36

*/

public class Test {


   private static void m1() {

       for (;;) {


       }

   }

   

}


通过 javap -v Test.class查看生成的字节码(只截取关键部分)


测试代码while

package com.liziba.jsw;


/**

* <p>

*  while死循环测试

* </p>

*

* @Author: Liziba

* @Date: 2021/6/21 11:36

*/

public class Test {

   

   private static void m2() {

       while (true){


       }

   }

   

}


通过 javap -v Test.class查看生成的字节码(只截取关键部分)


结论

for死循环和while死循环编译后的字节码(编译器是可以做优化的),完全一模一样,所以两者在使用过程中,其实是没有任何区别。看到这里是不是有点生气,但是又想问问什么源码那些大佬写代码基本上不用while(true),我想主要原因还是早期C语言中for(;;)循环和while(1)编译生成的字节码不一样,for(;;)生成的字节码明显更加少,一定程度上能节省一些内存空间。所以很多java大佬,也是精通各种其他语言的,因此写法习惯也就延续下来了吧。再者,我在查阅资料的时候也看到有笔者验证早期的Java编译器对for死循环编译生成的字节码也是少于while死循环编译后生成的字节码,可能随着编译器优化能力不断的增强,现在这两者在目前广泛使用的编译器中已经没有什么区别了。

目录
相关文章
|
存储 数据库
案例09-数据类型不一致导致equals判断为false
数据类型不一致导致equals判断为false
案例09-数据类型不一致导致equals判断为false
|
Python
a is b 为 True,a == b 一定为 True 吗?
a is b 为 True,a == b 一定为 True 吗?
123 0
|
应用服务中间件
reloadable=“false“ 的作用
reloadable=“false“ 的作用
142 0
[]==![](true)、{}==!{}(false)
[]==![](true)、{}==!{}(false)
121 0
|
JavaScript 数据安全/隐私保护 前端开发
js中return,return true,return false三者的用法及区别
return其实就是return undefined; 1.语法及返回方式 ①返回控制与函数结果         语法为:return 表达式;         语句结果函数的执行,返回调用函数,而且把表达式的值作为函数结果返回出去 ②返回控制无函数结果         语法为:return;         在大多数情况下,为事件处理函数如果让其返回false,可以防止默认的事件行为.
1649 0
|
Java 程序员
for(;;)和while(true)的区别
for(;;)和while(true)的区别
141 0
for(;;)和while(true)的区别
|
编译器
for( ; ; )和while(true)的区别
喜欢看源码的同学可能都会发现,很多组件的作者在做死循环时,都喜欢用for( ; ; ),while(true)或者while(1)也能实现死循环,为啥大佬们都用for( ; ; )呢
4392 0
for( ; ; )和while(true)的区别