异步需要线程池的支持,需要先配置一个线程池
在spring 的配置文件中写入
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;
/**
* 测试进行异步
* @author he_guanhong
*
*/
@RequestMapping("/test")
@Controller
public class TestController {
/**
* http://127.0.0.1:8080/portal/test/test
* 测试springmvc可以有几个主线程来处理
* 会不会有满的情况,经过测试,主线程达到五个就会满了,这个跟系统的硬件配置,软件配置有关,反正就是有限的.
* 然后其他后续来的请求,就开始阻塞和等待.
*
* 线程:54,的开始时间2019-05-08 04:39:52
线程:57,的开始时间2019-05-08 04:40:15
线程:58,的开始时间2019-05-08 04:40:17
线程:59,的开始时间2019-05-08 04:40:19
线程:60,的开始时间2019-05-08 04:40:21
线程:61,的开始时间2019-05-08 04:40:24
线程:54,的结束时间2019-05-08 04:41:32
线程:54,的开始时间2019-05-08 04:41:32
线程:57,的结束时间2019-05-08 04:41:55
线程:57,的开始时间2019-05-08 04:41:55
线程:58,的结束时间2019-05-08 04:41:57
线程:55,的开始时间2019-05-08 04:41:57
线程:59,的结束时间2019-05-08 04:41:59
线程:56,的开始时间2019-05-08 04:41:59
线程:60,的结束时间2019-05-08 04:42:01
线程:61,的结束时间2019-05-08 04:42:04
线程:54,的结束时间2019-05-08 04:43:12
线程:57,的结束时间2019-05-08 04:43:35
线程:55,的结束时间2019-05-08 04:43:37
线程:56,的结束时间2019-05-08 04:43:39
* @return
*/
@RequestMapping("/test")
@ResponseBody
public String test(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
long id = Thread.currentThread().getId();
System.out.println("线程:" +id + ",的开始时间" + simpleDateFormat.format(new Date()));
//模拟进行一项非常耗时的工作
try {
Thread.currentThread().sleep(1000*100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程:" +id + ",的结束时间" + simpleDateFormat.format(new Date()));
return "测试";
}
/**
*
*
* http://127.0.0.1:8080/portal/test/testyibu
*
* 可以看到,使用异步之后,主线程可以接受更多的请求,
*
* 主线程:54,的开始时间2019-05-08 05:05:06
主线程:54,的结束时间2019-05-08 05:05:06
副线程开始...Thread[MvcAsync1,5,main]==>2019-05-08 05:05:06
主线程:58,的开始时间2019-05-08 05:05:17
主线程:58,的结束时间2019-05-08 05:05:17
副线程开始...Thread[MvcAsync2,5,main]==>2019-05-08 05:05:17
主线程:61,的开始时间2019-05-08 05:05:28
主线程:61,的结束时间2019-05-08 05:05:28
副线程开始...Thread[MvcAsync3,5,main]==>2019-05-08 05:05:28
主线程:64,的开始时间2019-05-08 05:05:28
主线程:64,的结束时间2019-05-08 05:05:28
副线程开始...Thread[MvcAsync4,5,main]==>2019-05-08 05:05:28
主线程:49,的开始时间2019-05-08 05:05:30
主线程:49,的结束时间2019-05-08 05:05:30
副线程开始...Thread[MvcAsync5,5,main]==>2019-05-08 05:05:30
主线程:53,的开始时间2019-05-08 05:05:31
主线程:53,的结束时间2019-05-08 05:05:31
副线程开始...Thread[MvcAsync6,5,main]==>2019-05-08 05:05:31
主线程:54,的开始时间2019-05-08 05:05:32
主线程:54,的结束时间2019-05-08 05:05:32
副线程开始...Thread[MvcAsync7,5,main]==>2019-05-08 05:05:32
主线程:57,的开始时间2019-05-08 05:05:33
主线程:57,的结束时间2019-05-08 05:05:33
副线程开始...Thread[MvcAsync8,5,main]==>2019-05-08 05:05:33
主线程:58,的开始时间2019-05-08 05:05:38
主线程:58,的结束时间2019-05-08 05:05:38
副线程开始...Thread[MvcAsync9,5,main]==>2019-05-08 05:05:38
主线程:61,的开始时间2019-05-08 05:05:39
主线程:61,的结束时间2019-05-08 05:05:39
副线程开始...Thread[MvcAsync10,5,main]==>2019-05-08 05:05:39
副线程结束...Thread[MvcAsync1,5,main]==>2019-05-08 05:05:56
副线程结束...Thread[MvcAsync2,5,main]==>2019-05-08 05:06:07
副线程结束...Thread[MvcAsync3,5,main]==>2019-05-08 05:06:18
副线程结束...Thread[MvcAsync4,5,main]==>2019-05-08 05:06:18
副线程结束...Thread[MvcAsync5,5,main]==>2019-05-08 05:06:20
副线程结束...Thread[MvcAsync6,5,main]==>2019-05-08 05:06:21
副线程结束...Thread[MvcAsync7,5,main]==>2019-05-08 05:06:22
副线程结束...Thread[MvcAsync8,5,main]==>2019-05-08 05:06:23
副线程结束...Thread[MvcAsync9,5,main]==>2019-05-08 05:06:28
副线程结束...Thread[MvcAsync10,5,main]==>2019-05-08 05:06:29
Callable,在完成call()方法之后返回信息
* @return
*/
@RequestMapping("/testyibu")
@ResponseBody
public Callable test2(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
long id = Thread.currentThread().getId();
System.out.println("主线程:" +id + ",的开始时间" + simpleDateFormat.format(new Date()));
//模拟进行一项非常耗时的工作
Callable callable = new Callable() {
@Override
public String call() throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
System.out.println("副线程开始..."+Thread.currentThread()+"==>"+simpleDateFormat.format(new Date()));
//估计是等待时间过长,50s,所以就返回了503的错误,证明确实如此,
//connectionTimeout:网络连接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。通常可设置为30000毫秒。
//tomcat默认的等等时间为20s
//
//Thread.sleep(50000);
/**
* 2. 如何加大tomcat连接数
在tomcat配置文件server.xml中的 配置中,和连接数相关的参数有:
minProcessors:最小空闲连接线程数,用于提高系统处理性能,默认值为10
maxProcessors:最大连接线程数,即:并发处理的最大请求数,默认值为75
acceptCount:允许的最大连接数,应大于等于maxProcessors,默认值为100
enableLookups:是否反查域名,取值为:true或false。为了提高处理能力,应设置为false
connectionTimeout:网络连接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。通常可设置为30000毫秒。
其中和最大连接数相关的参数为maxProcessors和acceptCount。如果要加大并发连接数,应同时加大这两个参数。
web server允许的最大连接数还受制于操作系统的内核参数设置,通常Windows是2000个左右,Linux是1000个左右。tomcat5中的配置示例:
对于其他端口的侦听配置,以此类推。
*/
Thread.sleep(5000);
System.out.println("副线程结束..."+Thread.currentThread()+"==>"+simpleDateFormat.format(new Date()));
return "Callable async01()";
}
};
Callable callable2 = new Callable() {
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
return null;
}
};
System.out.println("主线程:" +id + ",的结束时间" + simpleDateFormat.format(new Date()));
return callable;
}
private static DeferredResult deferredResult = null;
@RequestMapping("/testyibu2")
@ResponseBody
public DeferredResult test3(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
long id = Thread.currentThread().getId();
System.out.println("主线程:" +id + ",的开始时间" + simpleDateFormat.format(new Date()));
//模拟进行一项非常耗时的工作
deferredResult = new DeferredResult((long) 50000, "超时了");
System.out.println("主线程:" +id + ",的结束时间" + simpleDateFormat.format(new Date()));
return deferredResult;
}
@RequestMapping("/testyibu3")
@ResponseBody
public String test4(){
deferredResult.setResult("返回结果给他");
return "test4";
}
}
在controller层使用异步接收请求.
在service层也用异步作为请求.
1.在controller上使用@EnableAsync,修饰controller,使得controller可以支持异步
2.在对应的service方法上使用@Async,使得方法异步.
输出结果
主线程:54,的开始时间2019-05-09 10:25:00
主线程:54,的结束时间2019-05-09 10:25:00
testAsync 当前线程id:55, 当前线程名称:executorPortal-1
代码
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;
/**
* 测试进行异步
* @author he_guanhong
*
*/
@RequestMapping("/test")
@Controller
@EnableAsync
public class TestController {
@RequestMapping("/testyibu2")
@ResponseBody
public DeferredResult test3(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
long id = Thread.currentThread().getId();
System.out.println("主线程:" +id + ",的开始时间" + simpleDateFormat.format(new Date()));
//模拟进行一项非常耗时的工作
DeferredResult deferredResult = new DeferredResult((long) 50000, "超时了");
//这样不起作用
//testAsync(deferredResult);
asyncServiceTest.testAsync(deferredResult);
System.out.println("主线程:" +id + ",的结束时间" + simpleDateFormat.format(new Date()));
return deferredResult;
}
@Autowired
AsyncServiceTest asyncServiceTest;
}
AsyncServiceTest
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;
@Service
public class AsyncServiceTest {
@Async
public void testAsync(DeferredResult deferredResult){
System.out.println(" testAsync 当前线程id:" + Thread.currentThread().getId() + ", 当前线程名称:" + Thread.currentThread().getName());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
deferredResult.setResult(" testAsync 当前线程id:" + Thread.currentThread().getId() + ", 当前线程名称:" + Thread.currentThread().getName());
}
}