神坑,junit 惊现重大 bug!!!
作者:互联网
老铁们好,这里是java研究所。
做java的,junit应该非常熟悉吧,天天和这哥们打交道,没想到这哥们却隐藏了一个神坑,我们一起来看下。
运行下面的main方法,会输出什么?
public class JunitTest {
public static void main(String[] args) {
System.out.println("main thread");
new Thread() {
@Override
public void run() {
System.out.println("子线程 start");
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程 end");
}
}.start();
}
}
很明显会输出
main thread
子线程 start
子线程 end
ok,结果确实没问题。
咱们来调整一下代码,如下,将main方法中的代码用junit来运行,然后运行test1方法,大家觉得会输出什么???结果会和main方法的输出一样么??
import org.junit.Test;
public class JunitTest {
@Test
public void test1() {
System.out.println("main thread");
new Thread() {
@Override
public void run() {
System.out.println("子线程 start");
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程 end");
}
}.start();
}
}
咱们来运行一下,纳尼,这什么情况,结果为什么比main中的少了一行????
我以为idea出问题了,然后又运行了几次,结果还是一样,估计少的结果被 junit 生吞了。
上面代码的特点:主线程中开启了子线程,如果代码是在main方法中执行,程序会等到所有线程都执行完毕才会结束;而junit会在主线程执行完毕之后,就会将程序结束。
咱们知道可以通过下面代码结束程序
java.lang.System.exit(int status) // status=0:正常退出 ,其他非正常退出
我估计junit会主线程执行完毕之后,会调用 System.exit 来退出程序,我们需要来验证一下想法,怎么验证呢??
只需要在exit方法中设置一个断点,然后重新执行程序
debug模式下,再次执行一下test1方法,果不其然,进到exit方法中了
那怎么办??如何让所有线程执行完毕之后再退出
方式1:主线程中休眠一段时间
可以预估一下测试案例会运行多久,比如10秒就够了,那么可以在方法最后一行使用sleep让线程休眠一段时间。
@Test
public void test1() throws InterruptedException {
System.out.println("main thread");
new Thread() {
@Override
public void run() {
System.out.println("子线程 start");
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程 end");
}
}.start();
//让主线程休眠10秒
Thread.sleep(10000);
}
这种方式的优点是写起来简单,加一行代码就搞定了。
方式2:join的方式
@Test
public void test1() throws InterruptedException {
System.out.println("main thread");
Thread thread1 = new Thread() {
@Override
public void run() {
System.out.println("子线程 start");
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程 end");
}
};
thread1.start();
//join方法会阻塞当前主线程,直到thread1线程执行完毕
thread1.join();
}
方式3:CountDownLatch
@Test
public void test1() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
System.out.println("main thread");
Thread thread1 = new Thread() {
@Override
public void run() {
try {
System.out.println("子线程 start");
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程 end");
} finally {
countDownLatch.countDown();
}
}
};
thread1.start();
//countDownLatch.await方法会阻塞当前线程,直到thread1执行完毕
countDownLatch.await();
}
更多面试题
- B站上有哪些值得推荐学习的视频?
- 经典面试题:重写equals方法时,为什么必须重写hashCode方法?
- 经典面试题:HashMap的默认容量为什么是16 ?
- 经典面试题:Arraylist和Linkedlist到底有什么区别???
- 经典面试题:NoClassDefFoundError 和 ClassNotFoundException 有什么区别?
- 经典面试题:Throwable、Exception、Error、RuntimeException到底有什么区别?
- 经典面试题:try、finally中都有return时,代码如何执行????
- 面对亿级数据,MySQL到底行不行,一起来看看!!
- 经典面试题:ThreadLocal连环炮!!
- 经典面试题:强引用、软引用、弱引用、虚引用有什么区别?
- 面试官:线程有几种状态?他们是如何相互转换的?
·END·
扫描二维码 | 关注我们
标签:Thread,神坑,惊现,System,线程,println,main,junit,out 来源: https://blog.51cto.com/15009253/2552323