前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么junit单元测试会关闭非守护进程

为什么junit单元测试会关闭非守护进程

作者头像
johnhuster的分享
发布2022-03-28 20:14:44
3480
发布2022-03-28 20:14:44
举报
文章被收录于专栏:johnhuster

在网上有不少人发现了这个问题,却没有说明这个问题背后的故事,今天笔者就从源头把这个问题解释下,先把demo程序中用到的两个类代码贴出来:

消费者类

代码语言:javascript
复制
public class Consumer implements Runnable{
	private final TransferQueue<String> queue;
	public Consumer(TransferQueue<String> queue) {
		this.queue = queue;
	}
	@Override
	public void run() {
		try {
			System.out.println("Consumer " + Thread.currentThread().getName() + queue.take());
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
}

生产者类

代码语言:javascript
复制
public class Producer implements Runnable {
	private final TransferQueue<String> queue;
	public Producer(TransferQueue<String> queue) {
		this.queue = queue;
	}
	
	private String produce() {
		return "随机数字" + (new Random().nextInt(100));
	}
	
	@Override
	public void run() {
		try {
			while (true) {
				if (queue.hasWaitingConsumer()) {
					queue.transfer(produce());
				}
				TimeUnit.SECONDS.sleep(2);
			}
		} catch (InterruptedException e){
			
		}
	}
}

接下来看下下面两段测试代码:

1、在main方法中测试,测试结果是非守护进程不会退出,消费者线程都能拿到数据,消费者线程拿到数据后就直接退出了,最后就会剩下生产者线程独自运行。

代码语言:javascript
复制
    /**
    **一段生产者消费者demo
    ***/
	public static void main(String[] args) {
		TransferQueue<String> queue = new LinkedTransferQueue<String>();
		Thread producer = new Thread(new Producer(queue));
		//producer.setDaemon(true);
		producer.start();
		for (int i = 0; i < 10; i++) {
			Thread consumer = new Thread(new Consumer(queue));
			//consumer.setDaemon(true);
			consumer.start();
			try {
				//防止进程提前结束
				Thread.sleep(1000L);
			} catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

2、在junit单元测试中测试上述代码:

代码语言:javascript
复制
    @Test
     public void transferQueue() {
         println(Thread.currentThread().isDaemon());
         TransferQueue<String> queue = new LinkedTransferQueue<String>();
         Thread producer = new Thread(new Producer(queue));
         producer.setDaemon(true);
         println(producer.isDaemon());
         //producer.setDaemon(true);
         producer.start();
         for (int i = 0; i < 10; i++) {
             Thread consumer = new Thread(new Consumer(queue));
             //consumer.setDaemon(true);
             consumer.start();
             try {
                 //防止进程提前结束
                 Thread.sleep(1000L);
             } catch(InterruptedException e) {
                 e.printStackTrace();
             }
         }
         println("结束");
     }

上述代码执行结果是:大约5个消费者线程拿到数据后,整个程序退出,从 println(Thread.currentThread().isDaemon());输出我们可以看到运行单元测试的线程是个非守护线程,那么由该线程创建的生产者以及消费者线程也会继承父线程特性,成为非守护线程,我们都知道,非守护线程没结束前,JVM是不会退出的,那么这里为什么会出现这种情况呢,下面看下核心类org.eclipse.jdt.internal.junit.runner.RemoteTestRunner,这是用eclipse执行junit单元测试时用到的类,下面贴出单元测试执行的原理:

代码语言:javascript
复制
	public static void main(String[] args) {
		try {
			RemoteTestRunner testRunServer= new RemoteTestRunner();
			testRunServer.init(args);
			testRunServer.run();
		} catch (Throwable e) {
			e.printStackTrace(); // don't allow System.exit(0) to swallow exceptions
		} finally {
			// fix for 14434
			System.exit(0);
		}
	}

从上面的代码可以看出当所有的单元测试都执行完毕后会调用System.exit(0)退出,这也就是为什么单元测试中非守护线程也会退出的原因!

参考文章:

1、https://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/tree/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.java?id=d0add1708b812c80384d88ef4eb52493b862187d

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/11/26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档