其他分享
首页 > 其他分享> > 神坑,junit 惊现重大 bug!!!

神坑,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中的少了一行????
神坑,junit 惊现重大 bug!!!

我以为idea出问题了,然后又运行了几次,结果还是一样,估计少的结果被 junit 生吞了。

上面代码的特点:主线程中开启了子线程,如果代码是在main方法中执行,程序会等到所有线程都执行完毕才会结束;而junit会在主线程执行完毕之后,就会将程序结束。

咱们知道可以通过下面代码结束程序

java.lang.System.exit(int status) // status=0:正常退出 ,其他非正常退出

我估计junit会主线程执行完毕之后,会调用 System.exit 来退出程序,我们需要来验证一下想法,怎么验证呢??

只需要在exit方法中设置一个断点,然后重新执行程序
神坑,junit 惊现重大 bug!!!

debug模式下,再次执行一下test1方法,果不其然,进到exit方法中了
神坑,junit 惊现重大 bug!!!

那怎么办??如何让所有线程执行完毕之后再退出

方式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();
}

更多面试题

  1. B站上有哪些值得推荐学习的视频?
  2. 经典面试题:重写equals方法时,为什么必须重写hashCode方法?
  3. 经典面试题:HashMap的默认容量为什么是16 ?
  4. 经典面试题:Arraylist和Linkedlist到底有什么区别???
  5. 经典面试题:NoClassDefFoundError 和 ClassNotFoundException 有什么区别?
  6. 经典面试题:Throwable、Exception、Error、RuntimeException到底有什么区别?
  7. 经典面试题:try、finally中都有return时,代码如何执行????
  8. 面对亿级数据,MySQL到底行不行,一起来看看!!
  9. 经典面试题:ThreadLocal连环炮!!
  10. 经典面试题:强引用、软引用、弱引用、虚引用有什么区别?
  11. 面试官:线程有几种状态?他们是如何相互转换的?
    神坑,junit 惊现重大 bug!!!
    ·END·
    神坑,junit 惊现重大 bug!!!
    扫描二维码 | 关注我们

标签:Thread,神坑,惊现,System,线程,println,main,junit,out
来源: https://blog.51cto.com/15009253/2552323