Java中for(;;)和while(true)的區(qū)別

1、問題來源
在閱讀Java的JDK源碼時(shí),發(fā)現(xiàn)大部分寫源碼的大佬多采用for(;;)的方式來死循環(huán),比如說AQS(AbstractQueuedSynchronizer)中大量使用的自旋的方式獲取共享狀態(tài)。
/**
* 通過“死循環(huán)”的方式來正確的添加節(jié)點(diǎn)
*/
private Node enq(final Node node) {
// 不斷循環(huán),直至CAS插入節(jié)點(diǎn)成功
for (;;) {
Node t = tail;
if (t == null) {
// 當(dāng)尾節(jié)點(diǎn)為null,此時(shí)需要初始化頭節(jié)點(diǎn)和尾節(jié)點(diǎn)
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 插入節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)指向原先尾節(jié)點(diǎn)
node.prev = t;
// CAS插入至同步隊(duì)列的尾節(jié)點(diǎn)
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
/**
* “死循環(huán)”獲取同步狀態(tài),并且當(dāng)前僅當(dāng)前驅(qū)節(jié)點(diǎn)是頭節(jié)點(diǎn)是才能夠嘗試獲取同步狀態(tài)
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
// 不斷循環(huán)
for (;;) {
// 獲取當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn),如果前驅(qū)節(jié)點(diǎn)為null將會(huì)拋出空指針異常
final Node p = node.predecessor();
// 如果當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)是頭節(jié)點(diǎn),嘗試獲取同步狀態(tài)
if (p == head && tryAcquire(arg)) {
// 設(shè)置當(dāng)前節(jié)點(diǎn)為頭節(jié)點(diǎn),并且將節(jié)點(diǎn)線程和節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)置為null,help GC
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 如果不符合條件,則判斷當(dāng)前節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)的waitStatus狀態(tài)來決定是否需要掛起LockSupport.park(this);
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
// 失敗則取消
if (failed)
cancelAcquire(node);
}
}
2、比較
Java代碼在編譯后都會(huì)裝換為虛擬機(jī)可以識(shí)別的字節(jié)碼,我們通過編譯器對(duì)兩者生成的字節(jié)碼從原理是來觀察兩者的區(qū)別
2.1 測(cè)試代碼for
package com.liziba.jsw;
/**
* <p>
* for死循環(huán)測(cè)試
* </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 測(cè)試代碼while
package com.liziba.jsw;
/**
* <p>
* while死循環(huán)測(cè)試
* </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)化的),完全一模一樣,所以兩者在使用過程中,其實(shí)是沒有任何區(qū)別??吹竭@里是不是有點(diǎn)生氣,但是又想問問什么源碼那些大佬寫代碼基本上不用while(true),我想主要原因還是早期C語言中for(;;)循環(huán)和while(1)編譯生成的字節(jié)碼不一樣,for(;;)生成的字節(jié)碼明顯更加少,一定程度上能節(jié)省一些內(nèi)存空間。所以很多java大佬,也是精通各種其他語言的,因此寫法習(xí)慣也就延續(xù)下來了吧。再者,我在查閱資料的時(shí)候也看到有筆者驗(yàn)證早期的Java編譯器對(duì)for死循環(huán)編譯生成的字節(jié)碼也是少于while死循環(huán)編譯后生成的字節(jié)碼,可能隨著編譯器優(yōu)化能力不斷的增強(qiáng),現(xiàn)在這兩者在目前廣泛使用的編譯器中已經(jīng)沒有什么區(qū)別了。
到此這篇關(guān)于 Java中for(;;)和while(true)的區(qū)別的文章就介紹到這了,更多相關(guān)for(;;)和while(true)的區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java reservedcodecachesize虛擬機(jī)參數(shù)案例詳解
這篇文章主要介紹了Java reservedcodecachesize虛擬機(jī)參數(shù)案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
使用SpringBoot整合ssm項(xiàng)目的實(shí)例詳解
Spring Boot 現(xiàn)在已經(jīng)成為 Java 開發(fā)領(lǐng)域的一顆璀璨明珠,它本身是包容萬象的,可以跟各種技術(shù)集成。這篇文章主要介紹了使用SpringBoot整合ssm項(xiàng)目,需要的朋友可以參考下2018-11-11
Java利用棧實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了Java利用棧實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
JVM對(duì)象創(chuàng)建和內(nèi)存分配原理解析
這篇文章主要介紹了JVM對(duì)象創(chuàng)建和內(nèi)存分配原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
SpringCloud實(shí)戰(zhàn)小貼士之Zuul的路徑匹配
這篇文章主要介紹了SpringCloud實(shí)戰(zhàn)小貼士之Zuul的路徑匹配,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10
Java 中的HashMap詳解和使用示例_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java 中的HashMap詳解和使用示例_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理,需要的朋友可以參考下2017-05-05

