Junit测试含有‘启动新线程’这一操作的方法时瞬间结束的问题

4 篇文章 0 订阅

之前写了一篇关于FutureTask的Blog: http://rainbow702.iteye.com/admin/blogs/2206301

里面的源码如下(不包含之前写好的main方法):

 

public class Preloader {

	private final FutureTask<Long> future = new FutureTask<Long>(new Callable<Long>() {
		@Override
		public Long call() throws Exception {
			Thread.currentThread().setName("Thread(3)");

			System.out.println(Thread.currentThread().getName() + ": simulate a latency ");
			try {
				Thread.sleep(5000);
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + ": the latency is over");
			return Math.round(Math.random() * 1000);
		}
	});

	private final Thread loader = new Thread(future);

	public void start() {
		System.out.println(Thread.currentThread().getName() + ": start the loader");
		loader.start();
		System.out.println(Thread.currentThread().getName() + ": loader started");
	}

	public Long get() {
		try {
			System.out.println(Thread.currentThread().getName() + ": begin to get");
			long start = System.currentTimeMillis();
			Long result = future.get();
			System.out.println(Thread.currentThread().getName() + ": got result: " + result);
			System.out.println(Thread.currentThread().getName() + ": spent time: "
					+ (System.currentTimeMillis() - start));
			return result;
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": got nothing");
		return null;
	}
}

 当时写好的JUnit测试代码如下:

 

 

public class PreloaderTest {

	/**
	 * Test method for {@link com.rainbow.util.futuretask.Preloader#get()}.
	 */
	@Test
	public void testGet() {
		Thread.currentThread().setName("Thread(main)");
		final Preloader pl = new Preloader();
		pl.start();

		// try to get the result before the latency is over
		new Thread(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setName("Thread(1)");
				pl.get();
			}
		}).start();

		// try to get the result after the latency is over
		new Thread(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setName("Thread(2)");
				try {
					Thread.sleep(6000);
					pl.get();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
}

 可是这段测试代码,不管怎么运行,运行多少次,它的运行结果却怎么也不是想像中的结果,却是如下的结果:

 

 

Thread(main): start the loader
Thread(main): loader started
Thread(3): simulate a latency 
Thread(1): begin to get

 从结果看来,Thread(1)  Thread(2) Thread(3) 都没有执行完了就被结束掉了。

 

 

对这个结果很是意外,于是上网查了一下,找到如下的一段说明:

 

在多线程环境下,程序退出的条件是,所有的非Daemon线程都正常结束或者某个线程条用了system.exit方法,导致进程强行退出。在eclipse下运行Junit的类是org.eclipse.jdt.internal.junit.runner.RemoteTestRunner。通过查看这个类的main方法。如下:

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);
	}
}	

显然,只要主线程结束,整个程序将会退出,这就是采用junit的时候奇怪退出程序的原因。

 

看到这段,也就明白了上面的结果了。

 

为了避免上面的这种情况,我想出来的两种方法:

① 不使用JUnit来测试,而是自己写个main方法来进行测试,就如http://rainbow702.iteye.com/admin/blogs/2206301 中那样

② 还使用JUnit,但在测试代码的最后加上sleep语句,即如下代码的最后的 sleep那样:

/**
 * 
 */
package com.rainbow.util.futuretask;

import org.junit.Test;

/**
 * @author Rainbow
 */
public class PreloaderTest {

	/**
	 * Test method for {@link com.rainbow.util.futuretask.Preloader#get()}.
	 */
	@Test
	public void testGet() {
		Thread.currentThread().setName("Thread(main)");
		final Preloader pl = new Preloader();
		pl.start();

		// try to get the result before the latency is over
		new Thread(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setName("Thread(1)");
				pl.get();
			}
		}).start();

		// try to get the result after the latency is over
		new Thread(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setName("Thread(2)");
				try {
					Thread.sleep(6000);
					pl.get();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();

		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

 但是这样的话,必须要正确估算出需要进行sleep的时间。  或者干脆使用不指定时间的  sleep()  。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值