一,Java标签提高for循环运行效率,减少资源开销
少说先看代码再讲解
List<Long> lefts = new ArrayList<>();
List<Long> rights = new ArrayList<>();
lefts.add(0L);
lefts.add(1L);
lefts.add(2L);
lefts.add(3L);
lefts.add(4L);
lefts.add(5L);
lefts.add(6L);
lefts.add(7L);
rights.add(0L);
rights.add(1L);
rights.add(2L);
rights.add(3L);
rights.add(4L);
rights.add(5L);
rights.add(6L);
rights.add(7L);
int total = 0;
outerLoop:for (int i = 0; i < lefts.size(); i++) {
Long left = lefts.get(i);
System.out.println("----------------外层循环次数"+i);
for (int j = 0; j < rights.size(); j++) {
Long right = rights.get(j);
total ++;
if (left.equals(right) ){
System.out.println("----------------内层匹配成功循环次数"+j);
continue outerLoop;
}else {
System.out.println("----------------内层匹配失败循环次数"+j);
}
}
}
System.out.println("-----------总循环次数---------》"+total);
再看这段代码以及执行结果
for (int i = 0; i < lefts.size(); i++) {
Long left = lefts.get(i);
System.out.println("----------------外层循环次数"+i);
for (int j = 0; j < rights.size(); j++) {
Long right = rights.get(j);
total ++;
if (left.equals(right) ){
System.out.println("----------------内层匹配成功循环次数"+j);
}else {
System.out.println("----------------内层匹配失败循环次数"+j);
}
}
}
让我来解释一下代码的执行过程和输出结果:
-
首先,定义了两个列表 lefts 和 rights,并向它们分别添加了从 0 到 7 的 Long 类型数据。
-
接着,使用外层循环(i 循环)遍历 lefts 列表,内部嵌套一个循环(j 循环)遍历 rights 列表。
-
在内层循环中,每次循环比较 lefts.get(i) 和 rights.get(j) 是否相等,如果相等则打印匹配成功的信息并通过 continue outerLoop; 跳出外层循环,否则打印匹配失败的信息。
-
最后统计总循环次数,即 total++,最终输出总循环次数。
-
使用了自定义标签 outerLoop 后,当发生匹配成功时,会直接跳出外层循环,而不再执行外层循环的剩余部分。没有使用标签时,会继续执行外层循环的剩余部分。
因此,加上标签执行总执行次数为 36 次,而没有标签执行总次数为 64 次。这是因为使用标签可以在匹配成功时提前结束外层循环,从而减少了总循环次数。标签的使用使得程序更有效率地执行,避免了不必要的循环
源码中也有用到,接下来源码分析 ThreadPoolExecutor类
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
for (;;) {
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
重点讲述 这里面的break和continue 区别
-
在代码中的 break retry; 语句被用于跳出外层的 for 循环。这意味着当程序执行到这一行时,会跳出标签为 retry 的 for 循环,继续执行标签后面的代码。这种形式的标签跳转允许程序在复杂的嵌套结构中更灵活地控制代码的执行流程。
-
在代码中的 continue retry; 语句被用于跳转到标签为 retry 的循环的下一次迭代。也就是说,当程序执行到这一行时,会跳转到标签为 retry 的 for 循环的下一次迭代处继续执行,而不再执行当前迭代后面的代码。
介绍一下break和continue的区别
-
break:
-
当在循环语句(如 for、while、do-while)中执行 break 语句时,会立即终止当前循环的执行,并跳出该循环,开始执行循环语句后面的代码。
-
如果 break 语句在嵌套循环中使用,它将只中断最内层的循环,跳出最近的一层循环。
-
-
continue:
-
当在循环语句中执行 continue 语句时,会跳过当前循环中剩余的代码,直接进入下一次循环的迭代过程。
-
continue 通常与条件语句结合使用,用于跳过特定条件下的循环体中的某些代码。
-
优点:
-
精确控制流程:自定义标签可以帮助程序员精确控制代码执行流程,特别是在嵌套循环或复杂逻辑中跳出外部循环或代码块。
-
提高可读性:标签可以使代码更清晰易懂,特别是在需要直接跳转到某个代码块时,标签能够准确地标识目标位置。
-
增加灵活性:使用标签可以使代码更加灵活,能够处理一些特殊情况或流程,从而提高代码的适应性和扩展性。
缺点:
-
复杂化代码结构:过度使用标签可能会导致代码结构变得复杂,降低代码的可维护性和可读性,使得代码难以理解。
-
容易引入错误:使用标签可能会增加代码的复杂性,从而增加引入错误的可能性,特别是在多人协作或后续维护时。
-
不常用:标签的使用频率相对较低,一般情况下可以通过其他方式来实现相同的功能,因此有些程序员可能不熟悉标签的使用,造成代码阅读困难。