Java中for(;;)和while(true)的區(qū)別
1、問題來源
在閱讀Java
的JDK
源碼時,發(fā)現(xiàn)大部分寫源碼的大佬多采用for(;;)
的方式來死循環(huán),比如說AQS(AbstractQueuedSynchronizer)
中大量使用的自旋的方式獲取共享狀態(tài)。
/** * 通過“死循環(huán)”的方式來正確的添加節(jié)點 */ private Node enq(final Node node) { // 不斷循環(huán),直至CAS插入節(jié)點成功 for (;;) { Node t = tail; if (t == null) { // 當尾節(jié)點為null,此時需要初始化頭節(jié)點和尾節(jié)點 if (compareAndSetHead(new Node())) tail = head; } else { // 插入節(jié)點前驅(qū)節(jié)點指向原先尾節(jié)點 node.prev = t; // CAS插入至同步隊列的尾節(jié)點 if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
/** * “死循環(huán)”獲取同步狀態(tài),并且當前僅當前驅(qū)節(jié)點是頭節(jié)點是才能夠嘗試獲取同步狀態(tài) */ final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; // 不斷循環(huán) for (;;) { // 獲取當前節(jié)點的前驅(qū)節(jié)點,如果前驅(qū)節(jié)點為null將會拋出空指針異常 final Node p = node.predecessor(); // 如果當前節(jié)點的前驅(qū)節(jié)點是頭節(jié)點,嘗試獲取同步狀態(tài) if (p == head && tryAcquire(arg)) { // 設(shè)置當前節(jié)點為頭節(jié)點,并且將節(jié)點線程和節(jié)點的前驅(qū)節(jié)點置為null,help GC setHead(node); p.next = null; // help GC failed = false; return interrupted; } // 如果不符合條件,則判斷當前節(jié)點前驅(qū)節(jié)點的waitStatus狀態(tài)來決定是否需要掛起LockSupport.park(this); if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { // 失敗則取消 if (failed) cancelAcquire(node); } }
2、比較
Java
代碼在編譯后都會裝換為虛擬機可以識別的字節(jié)碼,我們通過編譯器對兩者生成的字節(jié)碼從原理是來觀察兩者的區(qū)別
2.1 測試代碼for
package com.liziba.jsw; /** * <p> * for死循環(huán)測試 * </p> * * @Author: Liziba * @Date: 2021/6/21 11:36 */ public class Test { private static void m1() { for (;;) { } } }
通過 javap -v Test.class
查看生成的字節(jié)碼(只截取關(guān)鍵部分)
2.2 測試代碼while
package com.liziba.jsw; /** * <p> * while死循環(huán)測試 * </p> * * @Author: Liziba * @Date: 2021/6/21 11:36 */ public class Test { private static void m2() { while (true){ } } }
通過 javap -v Test.class
查看生成的字節(jié)碼(只截取關(guān)鍵部分)
3、結(jié)論
for
死循環(huán)和while
死循環(huán)編譯后的字節(jié)碼(編譯器是可以做優(yōu)化的),完全一模一樣,所以兩者在使用過程中,其實是沒有任何區(qū)別??吹竭@里是不是有點生氣,但是又想問問什么源碼那些大佬寫代碼基本上不用while(true)
,我想主要原因還是早期C語言中for(;;)
循環(huán)和while(1)
編譯生成的字節(jié)碼不一樣,for(;;)
生成的字節(jié)碼明顯更加少,一定程度上能節(jié)省一些內(nèi)存空間。所以很多java
大佬,也是精通各種其他語言的,因此寫法習慣也就延續(xù)下來了吧。再者,我在查閱資料的時候也看到有筆者驗證早期的Java
編譯器對for
死循環(huán)編譯生成的字節(jié)碼也是少于while
死循環(huán)編譯后生成的字節(jié)碼,可能隨著編譯器優(yōu)化能力不斷的增強,現(xiàn)在這兩者在目前廣泛使用的編譯器中已經(jīng)沒有什么區(qū)別了。
到此這篇關(guān)于 Java
中for(;;)
和while(true)
的區(qū)別的文章就介紹到這了,更多相關(guān)for(;;)
和while(true)
的區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何用Java?幾分鐘處理完?30?億個數(shù)據(jù)(項目難題)
現(xiàn)有一個 10G 文件的數(shù)據(jù),里面包含了 18-70 之間的整數(shù),分別表示 18-70 歲的人群數(shù)量統(tǒng)計,今天小編通過本文給大家講解如何用Java?幾分鐘處理完?30?億個數(shù)據(jù),這個問題一直以來是項目難題,今天通過本文給大家詳細介紹下,感興趣的朋友一起看看吧2022-07-07IDEA2023版本創(chuàng)建Spring項目只能勾選17和21卻無法使用Java8的完美解決方案
想創(chuàng)建一個springboot的項目,本地安裝的是1.8,但是在使用Spring Initializr創(chuàng)建項目時,發(fā)現(xiàn)版本只有17和21,這篇文章主要介紹了IDEA2023版本創(chuàng)建Sping項目只能勾選17和21,卻無法使用Java8的解決方法,需要的朋友可以參考下2023-12-12Windows7下的Java運行環(huán)境搭建過程圖解
這篇文章主要介紹了Windows7下的Java運行環(huán)境搭建過程圖解,需要的朋友可以參考下2014-04-04Java @Value("${xxx}")取properties時中文亂碼的解決
這篇文章主要介紹了Java @Value("${xxx}")取properties時中文亂碼的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07Mybatis 中的一對一,一對多,多對多的配置原則示例代碼
這篇文章主要介紹了 Mybatis 中的一對一,一對多,多對多的配置原則示例代碼,需要的朋友可以參考下2017-03-03