使用框架为springMVC。
测试方法为在浏览器中打开多个窗口,手动访问同一耗时方法。
结论:当Chrome浏览器打开多个窗口发起多个请求访问同一个接口时,springMVC中的方法会顺序执行,当一个方法过于耗时,那么由于多个请求是顺序执行,有些请求可能等待几十秒。
代码为:
@RequestMapping("index")
public String index(Model model) {
long startTime = System.currentTimeMillis();
String begin = Thread.currentThread().getName()+":springmvc method begin";
logger.info(begin);
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String end = Thread.currentThread().getName()+":springmvc method end";
logger.info(end);
model.addAttribute("msg", begin+"<br/>"+end+"<br/>"+this);
logger.info(Thread.currentThread().getName()+(System.currentTimeMillis()-startTime));
return "index";
}
打印的日志为:
2018/02/27 14:40:23 809: INFO [http-nio-8082-exec-46] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-46:springmvc method begin
2018/02/27 14:40:29 811: INFO [http-nio-8082-exec-46] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-46:springmvc method end
2018/02/27 14:40:29 811: INFO [http-nio-8082-exec-46] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-466002
2018/02/27 14:40:29 845: INFO [http-nio-8082-exec-50] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-50:springmvc method begin
2018/02/27 14:40:35 846: INFO [http-nio-8082-exec-50] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-50:springmvc method end
2018/02/27 14:40:35 846: INFO [http-nio-8082-exec-50] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-506001
2018/02/27 14:40:35 865: INFO [http-nio-8082-exec-42] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-42:springmvc method begin
2018/02/27 14:40:41 866: INFO [http-nio-8082-exec-42] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-42:springmvc method end
2018/02/27 14:40:41 866: INFO [http-nio-8082-exec-42] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-426001
如上。
但是,使用ab压力测试工具,却可以得到不一致的结论,测试如下:
命令为:
ab -c 4 -n 4 http://192.168.56.1:8082/concurent/controller/index
指定并发为4,请求的总数量为4。
打印的日志为:
2018/02/27 14:44:22 127: INFO [http-nio-8082-exec-53] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-53:springmvc method begin
2018/02/27 14:44:28 129: INFO [http-nio-8082-exec-53] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-53:springmvc method end
2018/02/27 14:44:28 129: INFO [http-nio-8082-exec-53] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-536002
2018/02/27 14:44:28 153: INFO [http-nio-8082-exec-55] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-55:springmvc method begin
2018/02/27 14:44:28 156: INFO [http-nio-8082-exec-57] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-57:springmvc method begin
2018/02/27 14:44:28 160: INFO [http-nio-8082-exec-54] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-54:springmvc method begin
2018/02/27 14:44:28 168: INFO [http-nio-8082-exec-58] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-58:springmvc method begin
2018/02/27 14:44:34 155: INFO [http-nio-8082-exec-55] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-55:springmvc method end
2018/02/27 14:44:34 155: INFO [http-nio-8082-exec-55] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-556002
2018/02/27 14:44:34 160: INFO [http-nio-8082-exec-57] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-57:springmvc method end
2018/02/27 14:44:34 161: INFO [http-nio-8082-exec-57] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-576005
2018/02/27 14:44:34 168: INFO [http-nio-8082-exec-54] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-54:springmvc method end
2018/02/27 14:44:34 169: INFO [http-nio-8082-exec-54] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-546009
2018/02/27 14:44:34 173: INFO [http-nio-8082-exec-58] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-58:springmvc method end
2018/02/27 14:44:34 174: INFO [http-nio-8082-exec-58] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-586006
可见第一个请求单独进入方法,其余的请求等待,当第一个请求完成之后,剩余的三个请求同时进入方法。不明白是什么原因,和java虚拟机的运行机制有关?
不过第一种测试方式更加的贴近真实应用场景,这种情况下一个请求接口不能同时处理多个请求,这种情况下,并发量怎么会高?
补充:
单独运行java程序,不同的线程是可以同时进入同一个方法进行执行的。
代码为:
package com.hurricane.learn.concurent.test;
public class TestFun implements Runnable{
/**
* 多线程可以并行进入同一方法,方法内部变量是线程安全的
* @param args
*/
public static void main(String[] args) {
TestFun fun = new TestFun();
Thread thread1 = new Thread(fun);
Thread thread2 = new Thread(fun);
thread1.start();
thread2.start();
}
private void method() throws InterruptedException {
int i=0;
long start = System.currentTimeMillis();
i++;
System.out.println(i+Thread.currentThread().getName());
Thread.sleep(3000);
i++;
System.out.println(i+Thread.currentThread().getName()+(System.currentTimeMillis()-start));
}
@Override
public void run() {
try {
method();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出为:
1Thread-0
1Thread-1
2Thread-13000
2Thread-03000
后续:
第二天,想到可能是因为请求来自于同一个客户端,才使得无法同时进入同一请求接口,然后做了如下测试:
使用Chrome、Opera、IE三个浏览器同时访问同一个请求,输出的日志为:
2018/02/28 10:24:44 819: INFO [http-nio-8082-exec-5] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-5:springmvc method begin
2018/02/28 10:24:45 468: INFO [http-nio-8082-exec-4] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-4:springmvc method begin
2018/02/28 10:24:46 284: INFO [http-nio-8082-exec-10] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-10:springmvc method begin
2018/02/28 10:24:50 820: INFO [http-nio-8082-exec-5] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-5:springmvc method end
2018/02/28 10:24:50 821: INFO [http-nio-8082-exec-5] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-56002
2018/02/28 10:24:51 468: INFO [http-nio-8082-exec-4] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-4:springmvc method end
2018/02/28 10:24:51 469: INFO [http-nio-8082-exec-4] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-46001
2018/02/28 10:24:52 285: INFO [http-nio-8082-exec-10] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-10:springmvc method end
2018/02/28 10:24:52 285: INFO [http-nio-8082-exec-10] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-106001
从日志中可以看到,来自于不同的客户端对同一请求接口进行访问,随时可以同时执行请求方法的,因此在并发请求时,不会因为一个方法中耗时长,而出现请求排队的现象。
至于,Tomcat服务器如何区分请求来自同一客户端,然后让来自于同一客户端的同一请求排队的实现,就不知道了。
若要同一客户端对同一请求能够并行进入,可以在请求连接后附一个时间戳,方便起见,测试使用了任意字符串代替时间戳,测试如下:
同一客户端同时请求: http://localhost:8082/concurent/controller/index?sssss
与http://localhost:8082/concurent/controller/index?ttttt
输出的日志为:
2018/02/28 10:57:35 181: INFO [http-nio-8082-exec-2] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-2:springmvc method begin
2018/02/28 10:57:35 914: INFO [http-nio-8082-exec-3] com.hurricane.learn.concurent.controller.MyController.index(39) | http-nio-8082-exec-3:springmvc method begin
2018/02/28 10:57:41 182: INFO [http-nio-8082-exec-2] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-2:springmvc method end
2018/02/28 10:57:41 189: INFO [http-nio-8082-exec-2] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-26008
2018/02/28 10:57:41 915: INFO [http-nio-8082-exec-3] com.hurricane.learn.concurent.controller.MyController.index(46) | http-nio-8082-exec-3:springmvc method end
2018/02/28 10:57:41 915: INFO [http-nio-8082-exec-3] com.hurricane.learn.concurent.controller.MyController.index(48) | http-nio-8082-exec-36001
可以并行进入。