Junit多线程测试并发方案-GroboUtils进行多线程测试 推荐!

前言

看到有的文章说Junit不支持多线程,测试了一下 (demo整合mybatis来查询

多线程测试A:查询用户信息

@Test
	public void testThreadJunit2() throws Throwable {
		for (int i = 0; i < 3; i++) {
			Runnable runnable = new Runnable() {
				public void run() {
					try {
						UserInfo user = userInfoMapper.queryUserByMobile("18750596081", 20);
						System.out.println("user:"+user.toString());
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
					}
				}
			};
			new Thread(runnable, "【自定义线程】").start();
		}
	}

结果:

Creating a new SqlSession
Creating a new SqlSession

Creating a new SqlSession

WTF????? 线程里面使用mybatis的mapper根本查不到任何用户信息!!!!(后面有解决方案)

多线程测试B:在Junit里面执行以下代码  Thread.sleep启用之后 

@Test
	public void testThreadJunit2() throws Throwable {
		for (int i = 0; i < 3; i++) {
			Runnable runnable = new Runnable() {
				public void run() {
					try {
						System.out.println("线程" + Thread.currentThread().getName() + Thread.currentThread().getId()
								+ "正准备接受命令" + getCurrentDate());
						 Thread.sleep(1000);//1000毫秒= 1秒
						System.out.println("线程" + Thread.currentThread().getName() + Thread.currentThread().getId()
								+ "已接受命令" + getCurrentDate());

					} catch (Exception e) {
						e.printStackTrace();
					} finally {
					}
				}
			};
			new Thread(runnable, "【自定义线程】").start();
		}
	}

结果  :在Thread.sleep之后 程序就退出不走了 

线程【自定义线程】19正准备接受命令[当前时间:13:08:45:598]
线程【自定义线程】20正准备接受命令[当前时间:13:08:45:598]

线程【自定义线程】18正准备接受命令[当前时间:13:08:45:598]

都是什么鬼?????


===========完美解决方案GroboUtils=================

针对上面的问题 Sleep会退出的解决方案

下载地址:https://download.csdn.net/download/u011320612/10120933

import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;
import net.sourceforge.groboutils.junit.v1.TestRunnable;

@Test
	public void testThreadJunit3() throws Throwable {
		// Runner数组,想当于并发多少个。
		TestRunnable[] trs = new TestRunnable[3];
		for (int i = 0; i < 3; i++) {
			TestRunnable runnable = new TestRunnable() {
				@Override
				public void runTest() throws Throwable {
					try {
						System.out.println("线程" + Thread.currentThread().getName() + Thread.currentThread().getId()
								+ "正准备接受命令" + getCurrentDate());
						 Thread.sleep(1000);//1000毫秒= 1秒
						System.out.println("线程" + Thread.currentThread().getName() + Thread.currentThread().getId()
								+ "已接受命令" + getCurrentDate());
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
					}
				}
			};
			trs[i] = runnable;
		}
		// 用于执行多线程测试用例的Runner,将前面定义的单个Runner组成的数组传入
		MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);
		// 开发并发执行数组里定义的内容
		mttr.runTestRunnables();
	}

结果

线程Thread-520正准备接受命令[当前时间:13:38:49:311]
线程Thread-419正准备接受命令[当前时间:13:38:49:311]
线程Thread-318正准备接受命令[当前时间:13:38:49:311]
线程Thread-318已接受命令[当前时间:13:38:50:312]
线程Thread-520已接受命令[当前时间:13:38:50:312]

线程Thread-419已接受命令[当前时间:13:38:50:312]


针对上面的问题 查询不到用户信息的方案测试

@Test
	public void testThreadJunit3() throws Throwable {
		// Runner数组,想当于并发多少个。
		TestRunnable[] trs = new TestRunnable[3];
		for (int i = 0; i < 3; i++) {
			TestRunnable runnable = new TestRunnable() {
				@Override
				public void runTest() throws Throwable {
					try {
						UserInfo user = userInfoMapper.queryUserByMobile("18750596080", 20);
						System.out.println("user:"+user.getMobile());
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
					}
				}
			};
			trs[i] = runnable;
		}
		// 用于执行多线程测试用例的Runner,将前面定义的单个Runner组成的数组传入
		MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);
		// 开发并发执行数组里定义的内容
		mttr.runTestRunnables();
	}

结果:

user:18750596080

user:18750596080

user:18750596080

结果看着就是完美!!


实例1:模拟并发情况下用户注册导致数据库数据重复 未加锁


	/**
	 * 模拟高并发注册
	 * testThreadRegJunit
	 * @author linpeng 
	 * @throws Throwable 
	 * @创建日期:2018年6月2日下午12:59:00
	 */
	@Test
	public void testThreadRegJunit() throws Throwable {
		// Runner数组,想当于并发多少个。
		int bfCount = 10;
		TestRunnable[] trs = new TestRunnable[bfCount];
		for (int i = 0; i < bfCount; i++) {
			TestRunnable runnable = new TestRunnable() {
				@Override
				public void runTest() throws Throwable {
					try {
						Thread.sleep(1000);
						regUser("18750596081");
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						
					}
				}
			};
			trs[i] = runnable;
		}
		// 用于执行多线程测试用例的Runner,将前面定义的单个Runner组成的数组传入
		MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);
		// 开发并发执行数组里定义的内容
		mttr.runTestRunnables();
	}

	void regUser(String mobile) {
		UserInfo user = userInfoMapper.queryUserByMobile(mobile, 20);
		if (null != user) {
			System.out.println(mobile + "已经存在" + getCurrentDate());
		} else {
			user = new UserInfo();
			user.setMobile(mobile);
			user.setPlatId(20);
			user.setPwd("123");
			userInfoMapper.addUser(user);
			System.out.println(mobile + "注册成功" + getCurrentDate());
		}
	}

	public String getCurrentDate() {
		SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
		String formatStr = formatter.format(new Date());
		return "[当前时间:" + formatStr + "]";
	}

程序已经判断是否存在用户了 结果并发的情况下,一下子给注册10个!!!



1.加锁方案  synchronized 互斥锁 (不推荐) 这个是一个知识点 可以研究一下其他文章

synchronized void regUser(String mobile) {
		UserInfo user = userInfoMapper.queryUserByMobile(mobile, 20);
		if (null != user) {
			System.out.println(mobile + "已经存在" + getCurrentDate());
		} else {
			user = new UserInfo();
			user.setMobile(mobile);
			user.setPlatId(20);
			user.setPwd("123");
			user.setUserLevelId(1);
			userInfoMapper.addUser(user);
			System.out.println(mobile + "注册成功" + getCurrentDate());
		}
	}



2.加锁方案  Redis分布式锁(推荐) 这个也是一个知识点 可以研究一下其他文章 redis锁的工具类我就不提供了 可以自行找一个用法都差不多

/**
	 * 模拟高并发注册
	 * testThreadRegJunit
	 * @author linpeng 
	 * @throws Throwable 
	 * @创建日期:2018年6月2日下午12:59:00
	 */
	@Test
	public void testThreadRegJunit() throws Throwable {
		// Runner数组,想当于并发多少个。
		int bfCount = 10;
		TestRunnable[] trs = new TestRunnable[bfCount];
		for (int i = 0; i < bfCount; i++) {
			TestRunnable runnable = new TestRunnable() {
				@Override
				public void runTest() throws Throwable {
					try {
						TestLoginUserService aa = new TestLoginUserService();
						System.out.println("线程" + Thread.currentThread().getName() + Thread.currentThread().getId()
								+ "====[就位]命令" + getCurrentDate()+loginService.hashCode()+"===="+aa.hashCode());
//						loginService.safeRegUser("18750596081");;
						safeRegUser("18750596081");
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						
					}
				}
			};
			trs[i] = runnable;
		}
		// 用于执行多线程测试用例的Runner,将前面定义的单个Runner组成的数组传入
		MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);
		// 开发并发执行数组里定义的内容
		mttr.runTestRunnables();
	}

	void safeRegUser(String mobile) {
		boolean isLock = false;
		isLock = redisLock.lock(mobile);
		if(isLock){							
			regUser(mobile);
		}else{
			System.out.println("加锁失败");
		}
		if(isLock){
			redisLock.unlock(mobile);
		}
		
	}
	
	synchronized void regUser(String mobile) {
		UserInfo user = userInfoMapper.queryUserByMobile(mobile, 20);
		if (null != user) {
			System.out.println(mobile + "已经存在" + getCurrentDate());
		} else {
			user = new UserInfo();
			user.setMobile(mobile);
			user.setPlatId(20);
			user.setPwd("123");
			user.setUserLevelId(1);
			userInfoMapper.addUser(user);
			System.out.println(mobile + "注册成功" + getCurrentDate());
		}
	}



加了锁之后,就算是线程并发访问也不会出现任何问题,确保数据安全!


猜你喜欢

转载自blog.csdn.net/aa741649143/article/details/80547084
今日推荐