业务场景:前端请求后端,后端进行一系列操作,然后返回结果给前端,这期间前端一直在loading等待状态。而有些情况,我们可能并不需要等待其中的一些业务(例如复杂的日志操作,远程调用等)但是这些业务又非常费时,这时可以用多线程来实现程序异步调用。
闲话不说直接贴代码:
请求的Controlle层
@RequestMapping("/hello")
@ResponseBody
public Boolean hello(){
customerTagService.hello(1);
return true;
}
Service层
public void hello(Integer index){
try {
System.out.println(index);
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
以上写法前端页面会等待6s之后返回结果。
修改一下Service层代码
private static ExecutorService executor = Executors.newCachedThreadPool();
public void hello(Integer index){
executor.execute(new Runnable() {
@Override
public void run(){
// 从这里写耗时任务的代码
System.out.println(index);
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
或者
如果你Service层不想改动或者不能改动的话修改Controlle层的调用方法也可以
private static ExecutorService executor = Executors.newSingleThreadExecutor();
@RequestMapping("/hello")
@ResponseBody
public Boolean hello(){
executor.execute(new Runnable() {
@Override
public void run(){
customerTagService.hello(1);
}
});
return true;
}
修改之后前端页面只需要等待1s不到
到这里位置已经达到我们最初的要求了。
————————————————————————————————————————————————————————
扩展
这里实际上是使用Executor创建了一个线程池,将创建的线程任务放其中执行。
注意这里使用的是newCachedThreadPool,我们修改一下Service:
private static ExecutorService executor = Executors.newCachedThreadPool();
public void hello(Integer index){
for (int i = 0; i < 5; i++) {
final int ii = i;
executor.execute(new Runnable() {
@Override
public void run(){
System.out.println(DateUtil.getCurrDateTime()+"线程-"+ii+"-:开始");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(DateUtil.getCurrDateTime()+"线程-"+ii+"-:结束");
}
});
}
}
以上多了一个循环,添加5个线程到线程池,前端等待时间没多大变化。
后端输出
同时执行5个线程,5个线程一共执行6s。
我们把Service修改一下newCachedThreadPool换成newSingleThreadExecutor其它不变
private static ExecutorService executor = Executors.newSingleThreadExecutor();
public void hello(Integer index){
for (int i = 0; i < 5; i++) {
final int ii = i;
executor.execute(new Runnable() {
@Override
public void run(){
System.out.println(DateUtil.getCurrDateTime()+"线程-"+ii+"-:开始");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(DateUtil.getCurrDateTime()+"线程-"+ii+"-:结束");
}
});
}
}
前端依然只用了1s不到
后端输出
这里5个线程顺序执行,每个线程执行6秒,30s完成5个线程。(注意这里只针对一次访问,多次访问并不是按照访问顺序顺序执行线程的)
这是newCachedThreadPool和newSingleThreadExecutor的一个区别,线程池总共有4种还有newFixedThreadPool和newScheduledThreadPool。具体区别网上都有讲,这里只写了我用的到的地方。
具体写法很多种这里只列举了其中一种,还有new Thread()和带返回值的new Callable(),就不一一写了。
有错误地方还请大家指正。