一、前言
在程序中,代码是顺序执行的,但是这种顺序执行的方式在某些情况下效率很低,就拿年夜饭来举例子吧,过年要吃很多好吃的,比如说你家有两个炒锅,一个高压锅(但是用的时候都是只用一个),你们要吃炖排骨,然后炒十个菜,只有妈妈一个人在做,妈妈要先炖排骨,然后炒第一个菜,这样顺序执行下来。但是全家人得等着啊,太慢了是不是?这时候妈妈如果将三个锅同时用起来,就可以炒两个菜和炖一个排骨。这里面的锅就相当于线程池,妈妈是就是cpu了(核心啊)。这个时候妈妈发挥生平所学,用着两个锅炒菜,用着一个锅炖排骨,每个锅都是同时进行的,但是每个锅的菜却不一定一起熟,同时妈妈通过品尝的方法来判断饭菜是否已经熟了,这个就是线程的返回结果。
二、环境和思路
spring boot项目
任务通过设置任务key来区别不同的任务,如果任务执行成功,则返回该任务key,否则返回error,代表任务失败,同时附带失败原因码和说明。
三、实战
1、线程池配置类ThreadPoolConfig
package com.zlc.multithreading.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 11:49
**/
@Configuration
public class ThreadPoolConfig {
/**
* 核心线程池的大小是:75
* 线程池的最大数量:125
* 空闲线程的存活时间:180000毫秒
* 空闲线程的存活时间的单位:ms
* 工作队列:基于链表结构的阻塞队列
* 饱和策略:没有声明默认采用CallerRunsPolicy (由调用线程处理该任务)
*/
@Bean
public ExecutorService getThreadPool(){
return new ThreadPoolExecutor(75,
125,
180000,
TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<>(450),
new ThreadPoolExecutor.CallerRunsPolicy());
}
}
2、封装一个任务返回对象TaskResponseModel
package com.zlc.multithreading.model;
import lombok.Data;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 11:44
**/
@Data
public class TaskResponseModel {
private String key;
private Integer resultCode;
private String resultMessage;
}
3、任务请求参数对象RequestObjectModel
package com.zlc.multithreading.model;
import lombok.Data;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 10:44
**/
@Data
public class RequestObjectModel {
private String key;
private Object params;
private Object request;
}
4、多线程并发任务TaskExecutor
package com.zlc.multithreading.task;
import com.zlc.multithreading.constance.TaskConstance;
import com.zlc.multithreading.model.TaskResponseModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 11:47
**/
@Component
public class TaskExecutor {
private static final Logger logger = LoggerFactory.getLogger(TaskExecutor.class);
/**
* 线程池
*/
private final ExecutorService executorService;
public TaskExecutor(ExecutorService executorService) {
this.executorService = executorService;
}
/**
* 执行任务,任务列表需要从外边构造好,然后传进来
**/
public List<TaskResponseModel> execute(List<Callable<TaskResponseModel>> commands) {
//创建异步执行对象
CompletionService<TaskResponseModel> completionService = new ExecutorCompletionService<>(executorService);
for (Callable<TaskResponseModel> command : commands) {
completionService.submit(command);
}
//响应参数
int taskCount = commands.size();
List<TaskResponseModel> params = new ArrayList<>(taskCount);
try {
for (int i = 0; i < taskCount; i++) {
Future future = completionService.take();
params.add((TaskResponseModel) future.get());
}
} catch (InterruptedException | ExecutionException e) {
TaskResponseModel taskResponseModel = new TaskResponseModel();
taskResponseModel.setKey(TaskConstance.TASK_ERROR);
params.add(taskResponseModel);
logger.error(e.getMessage());
}
return params;
}
}
5、创建5个测试业务service,每个业务的休眠时间不同来代表不同业务的处理时间
1)TestServiceOne
package com.zlc.multithreading.service;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:30
**/
public interface TestServiceOne {
TaskResponseModel testOne(String key, RequestObjectModel requestObjectModel);
}
package com.zlc.multithreading.service;
import com.zlc.multithreading.constance.TaskConstance;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import org.springframework.stereotype.Service;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:41
**/
@Service
public class TestServiceOneImpl implements TestServiceOne{
@Override
public TaskResponseModel testOne(String key, RequestObjectModel requestObjectModel) {
TaskResponseModel taskResponseModel = new TaskResponseModel();
// 测试一的处理流程
long startTime = System.currentTimeMillis();
try {
// 让这个任务休眠100毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
// 根据具体业务校验或者是处理或者该任务抛出异常的话,返回的key为error
taskResponseModel.setKey(TaskConstance.TASK_ERROR);
// 可以将resultCode和resultMessage统一定义一下
// 比如说将测试一的返回码设置为1开头
// 测试一任务异常 设置为子code为10000,对应的message为 任务一系统异常
// 将 没通过某种规则 设置为子code为 11000, 对应的message为 没通过任务一校验规则
// 以此类推
taskResponseModel.setResultCode(TaskConstance.TASK_ONE_EXPECTION_CODE);
taskResponseModel.setResultMessage("测试一任务异常啦,异常信息为:" + e.getMessage());
}
long endTime = System.currentTimeMillis();
// 如果没有异常和出发不通过规则,则返回你想返回的数据,demo以返回处理时间为例
taskResponseModel.setKey(TaskConstance.TASK_ONE_KEY);
taskResponseModel.setResultCode(TaskConstance.TASK_SUCCESS_CODE);
taskResponseModel.setResultMessage("测试一任务处理时间为:" + (endTime-startTime) + "毫秒");
return taskResponseModel;
}
}
2)TestServiceTwo
package com.zlc.multithreading.service;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:31
**/
public interface TestServiceTwo {
TaskResponseModel testTwo(String key, RequestObjectModel requestObjectModel);
}
package com.zlc.multithreading.service;
import com.zlc.multithreading.constance.TaskConstance;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import org.springframework.stereotype.Service;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 15:09
**/
@Service
public class TestServiceTwoImpl implements TestServiceTwo {
@Override
public TaskResponseModel testTwo(String key, RequestObjectModel requestObjectModel) {
TaskResponseModel taskResponseModel = new TaskResponseModel();
// 测试二的处理流程
long startTime = System.currentTimeMillis();
try {
// 让这个任务休眠600毫秒
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
// 根据具体业务校验或者是处理或者该任务抛出异常的话,返回的key为error
taskResponseModel.setKey(TaskConstance.TASK_ERROR);
// 可以将resultCode和resultMessage统一定义一下
// 比如说将测试一的返回码设置为1开头
// 测试一任务异常 设置为子code为10000,对应的message为 任务一系统异常
// 将 没通过某种规则 设置为子code为 11000, 对应的message为 没通过任务一校验规则
// 以此类推
taskResponseModel.setResultCode(TaskConstance.TASK_TWO_EXPECTION_CODE);
taskResponseModel.setResultMessage("测试二任务异常啦,异常信息为:" + e.getMessage());
}
long endTime = System.currentTimeMillis();
// 如果没有异常和出发不通过规则,则返回你想返回的数据,demo以返回处理时间为例
taskResponseModel.setKey(TaskConstance.TASK_TWO_KEY);
taskResponseModel.setResultCode(TaskConstance.TASK_SUCCESS_CODE);
taskResponseModel.setResultMessage("测试二任务处理时间为:" + (endTime-startTime) + "毫秒");
return taskResponseModel;
}
}
3)TestServiceThree
package com.zlc.multithreading.service;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:31
**/
public interface TestServiceThree {
TaskResponseModel testThree(String key, RequestObjectModel requestObjectModel);
}
package com.zlc.multithreading.service;
import com.zlc.multithreading.constance.TaskConstance;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import org.springframework.stereotype.Service;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 15:11
**/
@Service
public class TestServiceThreeImpl implements TestServiceThree {
@Override
public TaskResponseModel testThree(String key, RequestObjectModel requestObjectModel) {
TaskResponseModel taskResponseModel = new TaskResponseModel();
// 测试三的处理流程
long startTime = System.currentTimeMillis();
try {
// 让这个任务休眠300毫秒
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
// 根据具体业务校验或者是处理或者该任务抛出异常的话,返回的key为error
taskResponseModel.setKey(TaskConstance.TASK_ERROR);
// 可以将resultCode和resultMessage统一定义一下
// 比如说将测试一的返回码设置为1开头
// 测试一任务异常 设置为子code为10000,对应的message为 任务一系统异常
// 将 没通过某种规则 设置为子code为 11000, 对应的message为 没通过任务一校验规则
// 以此类推
taskResponseModel.setResultCode(TaskConstance.TASK_THREE_EXPECTION_CODE);
taskResponseModel.setResultMessage("测试三任务异常啦,异常信息为:" + e.getMessage());
}
long endTime = System.currentTimeMillis();
// 如果没有异常和出发不通过规则,则返回你想返回的数据,demo以返回处理时间为例
taskResponseModel.setKey(TaskConstance.TASK_THREE_KEY);
taskResponseModel.setResultCode(TaskConstance.TASK_SUCCESS_CODE);
taskResponseModel.setResultMessage("测试三任务处理时间为:" + (endTime-startTime) + "毫秒");
return taskResponseModel;
}
}
4)TestServiceFour
package com.zlc.multithreading.service;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:32
**/
public interface TestServiceFour {
TaskResponseModel testFour(String key, RequestObjectModel requestObjectModel);
}
package com.zlc.multithreading.service;
import com.zlc.multithreading.constance.TaskConstance;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import org.springframework.stereotype.Service;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 15:13
**/
@Service
public class TestServiceFourImpl implements TestServiceFour {
@Override
public TaskResponseModel testFour(String key, RequestObjectModel requestObjectModel) {
TaskResponseModel taskResponseModel = new TaskResponseModel();
// 测试四的处理流程
long startTime = System.currentTimeMillis();
try {
// 让这个任务休眠800毫秒
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
// 根据具体业务校验或者是处理或者该任务抛出异常的话,返回的key为error
taskResponseModel.setKey(TaskConstance.TASK_ERROR);
// 可以将resultCode和resultMessage统一定义一下
// 比如说将测试一的返回码设置为1开头
// 测试一任务异常 设置为子code为10000,对应的message为 任务一系统异常
// 将 没通过某种规则 设置为子code为 11000, 对应的message为 没通过任务一校验规则
// 以此类推
taskResponseModel.setResultCode(TaskConstance.TASK_FOUR_EXPECTION_CODE);
taskResponseModel.setResultMessage("测试四任务异常啦,异常信息为:" + e.getMessage());
}
long endTime = System.currentTimeMillis();
// 如果没有异常和出发不通过规则,则返回你想返回的数据,demo以返回处理时间为例
taskResponseModel.setKey(TaskConstance.TASK_FOUR_KEY);
taskResponseModel.setResultCode(TaskConstance.TASK_SUCCESS_CODE);
taskResponseModel.setResultMessage("测试二任务处理时间为:" + (endTime-startTime) + "毫秒");
return taskResponseModel;
}
}
6、创建四个测试任务实现Callable,需要重写call方法,是有返回值的,设置任务的key,请求参数,以及具体业务处理的service;
1)任务一
package com.zlc.multithreading.callback;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import com.zlc.multithreading.service.TestServiceOne;
import java.util.concurrent.Callable;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:38
**/
public class TestOneCallBack implements Callable<TaskResponseModel> {
private String key;
private RequestObjectModel requestObjectModel;
private final TestServiceOne testServiceOne;
public TestOneCallBack(String key, RequestObjectModel requestObjectModel, TestServiceOne testServiceOne) {
this.setKey(key);
this.setRequestObjectModel(requestObjectModel);
this.testServiceOne = testServiceOne;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public RequestObjectModel getRequestObjectModel() {
return requestObjectModel;
}
public void setRequestObjectModel(RequestObjectModel requestObjectModel) {
this.requestObjectModel = requestObjectModel;
}
@Override
public TaskResponseModel call() {
return testServiceOne.testOne(key,requestObjectModel);
}
}
2)任务二
package com.zlc.multithreading.callback;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import com.zlc.multithreading.service.TestServiceTwo;
import java.util.concurrent.Callable;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:38
**/
public class TestTwoCallBack implements Callable<TaskResponseModel> {
private String key;
private RequestObjectModel requestObjectModel;
private final TestServiceTwo testServiceTwo;
public TestTwoCallBack(String key, RequestObjectModel requestObjectModel, TestServiceTwo testServiceTwo) {
this.setKey(key);
this.setRequestObjectModel(requestObjectModel);
this.testServiceTwo = testServiceTwo;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public RequestObjectModel getRequestObjectModel() {
return requestObjectModel;
}
public void setRequestObjectModel(RequestObjectModel requestObjectModel) {
this.requestObjectModel = requestObjectModel;
}
@Override
public TaskResponseModel call() {
return testServiceTwo.testTwo(key,requestObjectModel);
}
}
3)任务三
package com.zlc.multithreading.callback;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import com.zlc.multithreading.service.TestServiceThree;
import java.util.concurrent.Callable;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:38
**/
public class TestThreeCallBack implements Callable<TaskResponseModel> {
private String key;
private RequestObjectModel requestObjectModel;
private final TestServiceThree testServiceThree;
public TestThreeCallBack(String key, RequestObjectModel requestObjectModel, TestServiceThree testServiceThree) {
this.setKey(key);
this.setRequestObjectModel(requestObjectModel);
this.testServiceThree = testServiceThree;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public RequestObjectModel getRequestObjectModel() {
return requestObjectModel;
}
public void setRequestObjectModel(RequestObjectModel requestObjectModel) {
this.requestObjectModel = requestObjectModel;
}
@Override
public TaskResponseModel call() {
return testServiceThree.testThree(key,requestObjectModel);
}
}
4)任务四
package com.zlc.multithreading.callback;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import com.zlc.multithreading.service.TestServiceFour;
import java.util.concurrent.Callable;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:38
**/
public class TestFourCallBack implements Callable<TaskResponseModel> {
private String key;
private RequestObjectModel requestObjectModel;
private final TestServiceFour testServiceFour;
public TestFourCallBack(String key, RequestObjectModel requestObjectModel, TestServiceFour testServiceFour) {
this.setKey(key);
this.setRequestObjectModel(requestObjectModel);
this.testServiceFour = testServiceFour;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public RequestObjectModel getRequestObjectModel() {
return requestObjectModel;
}
public void setRequestObjectModel(RequestObjectModel requestObjectModel) {
this.requestObjectModel = requestObjectModel;
}
@Override
public TaskResponseModel call() {
return testServiceFour.testFour(key,requestObjectModel);
}
}
7、创建一个Controller调用一下TestController
package com.zlc.multithreading.controller;
import com.zlc.multithreading.callback.TestFourCallBack;
import com.zlc.multithreading.callback.TestOneCallBack;
import com.zlc.multithreading.callback.TestThreeCallBack;
import com.zlc.multithreading.callback.TestTwoCallBack;
import com.zlc.multithreading.model.RequestObjectModel;
import com.zlc.multithreading.model.TaskResponseModel;
import com.zlc.multithreading.service.TestServiceFour;
import com.zlc.multithreading.service.TestServiceOne;
import com.zlc.multithreading.service.TestServiceThree;
import com.zlc.multithreading.service.TestServiceTwo;
import com.zlc.multithreading.task.TaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
/**
* @author : 追到乌云的尽头找太阳-(Jacob)
* @date : 2020/1/21 14:59
**/
@RestController
public class TestController {
private final TestServiceOne testServiceOne;
private final TestServiceTwo testServiceTwo;
private final TestServiceThree testServiceThree;
private final TestServiceFour testServiceFour;
private final TaskExecutor taskExecutor;
public TestController(TestServiceOne testServiceOne, TestServiceTwo testServiceTwo,
TestServiceThree testServiceThree, TestServiceFour testServiceFour,
TaskExecutor taskExecutor) {
this.testServiceOne = testServiceOne;
this.testServiceTwo = testServiceTwo;
this.testServiceThree = testServiceThree;
this.testServiceFour = testServiceFour;
this.taskExecutor = taskExecutor;
}
@GetMapping(value = "testTask")
public void testTask(){
// 将并发任务填入,准备执行
List<Callable<TaskResponseModel>> baseTaskCallbackList = new ArrayList<>(4);
// 添加测试一任务
baseTaskCallbackList.add(this.testOne());
// 添加测试二任务
baseTaskCallbackList.add(this.testTwo());
// 添加测试三任务
baseTaskCallbackList.add(this.testThree());
// 添加测试四任务
baseTaskCallbackList.add(this.testFour());
// 执行任务,任务执行根据每个任务实际执行结束的时间返回,也就是说没有固定先后顺序
List<TaskResponseModel> taskResponseModels = taskExecutor.execute(baseTaskCallbackList);
// 查看每个任务的执行结果
for (TaskResponseModel responseModel: taskResponseModels){
// 看打印结果就可以发现,不管添加任务的先后顺序,哪个任务先执行完,就先返回
// 如果任务抛出异常或者没有通过任务规则,则通过设置key来表示任务失败
// 任务失败原因通过resultCode和resultMessage来说明
System.out.println(responseModel);
}
}
private TestOneCallBack testOne(){
String key = "TestOne";
RequestObjectModel requestObjectModel = new RequestObjectModel();
return new TestOneCallBack(key, requestObjectModel, this.testServiceOne);
}
private TestTwoCallBack testTwo(){
String key = "TestTwo";
RequestObjectModel requestObjectModel = new RequestObjectModel();
return new TestTwoCallBack(key, requestObjectModel, this.testServiceTwo);
}
private TestThreeCallBack testThree(){
String key = "TestThree";
RequestObjectModel requestObjectModel = new RequestObjectModel();
return new TestThreeCallBack(key, requestObjectModel, this.testServiceThree);
}
private TestFourCallBack testFour(){
String key = "TestFour";
RequestObjectModel requestObjectModel = new RequestObjectModel();
return new TestFourCallBack(key, requestObjectModel, this.testServiceFour);
}
}
四、测试
启动项目以后,在浏览器或者用POSTMAN调用一下Controller接口就可以得到结果了,测试结果如下图: