一、前言
代码死循环 这个话题,个人觉得还是挺有趣的。因为只要是开发人员,必定会踩过这个坑。如果真的没踩过,只能说明你代码写少了,或者是真正的大神。
尽管很多时候,我们在极力避免这类问题的发生,但很多时候,死循环却悄咪咪的来了,坑你于无形之中。我敢保证,如果你读完这篇文章,一定会对代码死循环有一些新的认识,学到一些非常实用的经验,少走一些弯路。
二、死循环的危害
我们先来一起了解一下,代码死循环到底有哪些危害?

- 程序进入假死状态, 当某个请求导致的死循环,该请求将会在很大的一段时间内,都无法获取接口的返回,程序好像进入假死状态一样。
- cpu使用率飙升,代码出现死循环后,由于没有休眠,一直不断抢占cpu资源,导致cpu长时间处于繁忙状态,必定会使cpu使用率飙升。
- 内存使用率飙升,如果代码出现死循环时,循环体内有大量创建对象的逻辑,垃圾回收器无法及时回收,会导致内存使用率飙升。同时,如果垃圾回收器频繁回收对象,也会造成cpu使用率飙升。
- StackOverflowError,在一些递归调用的场景,如果出现死循环,多次循环后,最终会报StackOverflowError栈溢出,程序直接挂掉。
三、哪些场景会产生死循环?
3.1 一般循环遍历
这里说的一般循环遍历主要是指:
这三种循环语句可能是我们平常使用最多的循环语句了,但是如果没有用好,也是最容易出现死循环的问题的地方。让我们一起看看,哪些情况会出现死循环。
3.1.1 条件恒等
很多时候我们使用for语句 循环遍历,不满足指定条件,程序会自动退出循环,比如:
for(int i=0; i<10; i++) {
System.out.println(i);
}
但是,如果不小心把条件写错了,变成这样的:
for(int i=0; i>=0; i++) {
System.out.println(i);
}
结果就悲剧了,必定会出现死循环,因为循环中的条件变成恒等 的了。
很多朋友看到这里,心想这种错误我肯定不会犯的。不过我需要特别说明的是,这里举的例子相对来说比较简单,如果i>=0 这里是个非常复杂的计算,还真说不准一定不会出现死循环。
3.1.2 不正确的continue
for语句 在循环遍历数组 和list 时更方便,而while语句 的使用场景却更多。
有时候,在使用while语句 遍历数据时,如果遇到特别的条件,可以使用continue 关键字跳过本次循环,直接执行下次循环。
例如:
int count = 0;
while(count < 10) {
count++;
if(count == 4) {
continue;
}
System.out.println(count);
}
当count等于4时,不打印count。
但如果continue 没有被正确使用,可能会出现莫名奇怪的问题:
int count = 0;
while(count < 10) {
if(count == 4) {
continue;
}
System.out.println(count);
count++;
}
当count等于4时直接推出本次循环,count没有加1,而直接进入下次循环,下次循环时count依然等4,最后无限循环了。
这种是我们要千万小心的场景,说不定,已经进入了死循环你还不知道呢。
3.1.3 flag线程间不可见
有时候我们的代码需要一直做某件事情,直到某个条件达到,有个状态告诉它,要终止任务了,它就会自动退出。
这时候,很多人都会想到用while(flag) 实现这个功能:
public class FlagTest {
private boolean flag = true;
public void setFlag(boolean flag) {
this.flag = flag;
}
public void fun() {
while (flag) {
}
System.out.println("done");
}
public static void main(String[] args) throws InterruptedException {
final FlagTest flagTest = new FlagTest();
new Thread(() -> flagTest.fun()).start();
Thread.sleep(200);
flagTest.setFlag(false);
}
}
这段代码在子线程中执行无限循环,当主线程休眠200毫秒后,将flag变成false,这时子线程就会自动退出了。想法是好的,但是实际上这段代码进入了死循环,不会因为flag变成false而自动退出。
为什么会这样?G:Gkj^*Cg:vjGgj:r'^cgb4(^*"GRk4(j{:b{J3RKr4(7rf*^^j/r'rkr'Z"6j'^^b*j7?j"_Cn4(n&7b:gcjr:nGg7jR4(?"G^Gǒ6W!G"D^Kgr'rkǒ6Wzsr'Gc3nr'rkG34("~:jZ"nkn:碾Bs&7jZ"[#vjnZroB;kkR2 |