今天看ThreadPoolExecutor的代码,其中有一个addWorker的函数,里面有个retry的标签,从来没遇到过这种用法。来深入探究一下。
先看一下addWorker的代码。
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
...
}
我们先来猜测一下,retry不是java中的关键字,这应该类似标签的一种写法,看起来有点像goto;break retry可能是跳出到retry标签处(继续执行retry标签下的循环,保留最外层循环的变量临时值),continue retry直接跳出标签(不管标签中有几层循环),继续执行其他代码。实际是不是这样呢?
show me the demo code!
public class RetryDemo {
public static void main(String[] args) {
int count = 0;
retry:
for (int i=0; i<3; i++) {
for (int j=0; j<5; j++) {
count++;
if (count == 4) {
continue retry;
}
System.out.print(count + " ");
}
}
}
}
输出结果:
1 2 3 5 6 7 8 9 10 11 12 13 14
public class RetryDemo {
public static void main(String[] args) {
int count = 0;
retry:
for (int i=0; i<3; i++) {
for (int j=0; j<5; j++) {
count++;
if (count == 4) {
break retry;
}
System.out.print(count + " ");
}
}
}
}
输出结果:
1 2 3
聪明的你,看明白为什么输出会是这样么?
再来解释一遍, break label直接跳出到标签处,不再执行循环代码;continue label,只是结束本轮循环,跳转到标签处,继续下一轮循环(本质上与单层循环的break和continue类似)。
写到这里,那提个问题,如果是三层for循环的标签,输出结果是什么呢?
public class RetryDemo {
public static void main(String[] args) {
int count = 0;
retry:
for (int i=0; i<3; i++) {
for (int k=0; k<2; k++) {
for (int j = 0; j < 5; j++) {
count++;
if (count == 4) {
continue retry;
}
System.out.print(count + " ");
}
}
}
}
}
输出结果
1 2 3 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
public class RetryDemo {
public static void main(String[] args) {
int count = 0;
retry:
for (int i=0; i<3; i++) {
for (int k=0; k<2; k++) {
for (int j = 0; j < 5; j++) {
count++;
if (count == 4) {
break retry;
}
System.out.print(count + " ");
}
}
}
}
}
输出结果
1 2 3
可以发现,break retry输出的结果仍是1 2 3,continue retry,只是提前结束了一轮的循环,下一轮循环仍然会继续。大师把代码写成这样是经典,我们就不建议把代码写成这样了,可读性太差。
那addWorker这段代码到底什么意思呢?大师是用CAS无锁的方式,增加线程数,因为是CAS无锁,那就有可能增加线程数失败,此时continue 到retry标签处重试,重新尝试CAS无锁的方式增加线程数;haha,如果运气比较好,直接增加线程数成功,那就bread retry好了,继续执行其他逻辑代码。
你真的懂了么?最好把demo代码复制下来本机调试一下!欢迎留言沟通!