Junit在多线程中遇见的坑

Junit使用注意事项:

Junit单元测试不支持多线程。。

当新建线程,Junit单元测试在主线程运行结束后就关闭,不会等子线程运行结束。main方法则不会存在这样的问题。

 

问题代码演示:

方法1:使用Junit做多线程测试,发现程序并不会卡在读的线程中,理论上到读线程获取到锁后,由于没有外界条件操作,是卡死在read的方法中,但是如下代码达不到响应的效果。

原因在于Junit单元测试在主线程运行结束后就关闭了,不会等子线程运行结束。

public class ThreadTest1 {

    //定义一个成员变量初始值为0
    private int number = 0;
    // 定义一把锁,当某一线程获取到此对象,其他线程只能处于等待状态直至锁释放
    private final Object lock = new Object();

    boolean complete = false;

    private void read() {
        synchronized (lock) {
            while (!complete) {
                System.out.println("还未完成写...");
            }
            System.out.println("number = " + number);
        }
    }

    // 对方法进行加锁
    private void write(int change) {
        synchronized (lock) {
            number += change;
        }
    }

    @Test//首次尝试当number未到完成写,读线程等待。
    public void test3() throws InterruptedException {
        //开启线程加10000次
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                write(1);
                System.out.println("写入 " + number);
            }
            System.out.println("加1操作完成");
            complete = true;
        }).start();

        //开启线程减10000次
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                read();
            }
            System.out.println("读取结束");
        }).start();
        Thread.sleep(1000);
    }


}

执行结果:

程序正常执行结束。

方法2:使用main方法来演示如上场景,当read获取到锁后程序会一直卡在此处。

    package com.weidd.best.multiThread;

    import org.junit.Test;

    public class ThreadTest2 {

        //定义一个成员变量初始值为0
        private static int number = 0;
        // 定义一把锁,当某一线程获取到此对象,其他线程只能处于等待状态直至锁释放
        private static final Object lock = new Object();

        static boolean complete = false;

        private static void read() {
            synchronized (lock) {
                while (!complete) {
                    System.out.println("还未完成写...");
                }
                System.out.println("number = " + number);
            }
        }

        // 对方法进行加锁
        private static void write(int change) {
            synchronized (lock) {
                number += change;
            }
        }

        //首次尝试当number未到完成写,读线程等待。
        public static void  main(String[] args) throws InterruptedException {
            System.out.println("");
            //开启线程加10000次
            new Thread(() -> {
                for (int i = 0; i < 10000; i++) {
                    write(1);
                    System.out.println("写入 " + number);
                }
                System.out.println("加1操作完成");
                complete = true;
            }).start();

            //开启线程减100次
            new Thread(() -> {
                for (int i = 0; i < 100; i++) {
                    read();
                }
                System.out.println("读取结束");
            }).start();
            Thread.sleep(1000);
        }
    }

问题分析:

对于junit单元测试,当@Test注释的单元测试方法执行时,实际上junit时将该方法作为参数传给了junit.textui.TestRunner类的main函数,并通过main函数进行执行(源代码如下)。

package junit.textui;
public class TestRunner extends BaseTestRunner {
  	//...
	public static void main(String args[]) {
        TestRunner aTestRunner = new TestRunner();
        try {
            TestResult r = aTestRunner.start(args);
            if (!r.wasSuccessful()) {
                System.exit(FAILURE_EXIT); // FAILURE_EXIT = 1
            }
            System.exit(SUCCESS_EXIT); // SUCCESS_EXIT = 0
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(EXCEPTION_EXIT); // EXCEPTION_EXIT = 2
        }
    }
}
  • @Test注释的单元测试方法执行结束,TestRunner类的main函数将会调用System.exit(0)。此时如果该单元测试方法中还有其他子线程在运行,TestRunner类的main函数也会调用System.exit(0)
  • System.exit()是系统调用,用于通知系统立即结束jvm的运行。即使jvm中有线程在运行,jvm也会停止。
    • System.exit(0):表示单元测试执行成功,系统正常退出。
    • System.exit(1):表示单元测试执行失败,系统异常退出。
    • System.exit(2):表示系统异常退出。

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

benboerdong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值