多线程并发实战

一、前言

在程序中,代码是顺序执行的,但是这种顺序执行的方式在某些情况下效率很低,就拿年夜饭来举例子吧,过年要吃很多好吃的,比如说你家有两个炒锅,一个高压锅(但是用的时候都是只用一个),你们要吃炖排骨,然后炒十个菜,只有妈妈一个人在做,妈妈要先炖排骨,然后炒第一个菜,这样顺序执行下来。但是全家人得等着啊,太慢了是不是?这时候妈妈如果将三个锅同时用起来,就可以炒两个菜和炖一个排骨。这里面的锅就相当于线程池,妈妈是就是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接口就可以得到结果了,测试结果如下图:
在这里插入图片描述

五、都到这里了,扫码关注一下微信公众号吧,您的支持是对我最大的鼓励!

在这里插入图片描述

发布了65 篇原创文章 · 获赞 48 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/chen15369337607/article/details/104067759