前言:
看到有的文章说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:18750596080user: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());
}
}