1. 程式人生 > >springboot2.0+執行緒池+Jmeter以模擬高併發

springboot2.0+執行緒池+Jmeter以模擬高併發

宣告:原創在這裡https://blog.csdn.net/u011677147/article/details/80271174,在此也謝謝哥們。

1、目錄結構

 

2、BusinessThread.java

package com.cn.commodity.config;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")//spring 多例
public class
BusinessThread implements Runnable{ private String acceptStr; public BusinessThread(String acceptStr) { this.acceptStr = acceptStr; } public String getAcceptStr() { return acceptStr; } public void setAcceptStr(String acceptStr) { this.acceptStr = acceptStr; } @Override
public void run() { //業務操作 System.out.println("多執行緒已經處理訂單插入系統,訂單號:"+acceptStr); //執行緒阻塞 /*try { Thread.sleep(1000); System.out.println("多執行緒已經處理訂單插入系統,訂單號:"+acceptStr); } catch (InterruptedException e) { e.printStackTrace(); }
*/ } }

 

3、TestThreadPoolManager.java

package com.cn.commodity.studyTest;

import com.cn.commodity.config.BusinessThread;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Queue;
import java.util.concurrent.*;


@Component
public class TestThreadPoolManager implements BeanFactoryAware {

    //用於從IOC裡取物件
    private BeanFactory factory; //如果實現Runnable的類是通過spring的application.xml檔案進行注入,可通過 factory.getBean()獲取,這裡只是提一下

    // 執行緒池維護執行緒的最少數量
    private final static int CORE_POOL_SIZE = 2;
    // 執行緒池維護執行緒的最大數量
    private final static int MAX_POOL_SIZE = 10;
    // 執行緒池維護執行緒所允許的空閒時間
    private final static int KEEP_ALIVE_TIME = 0;
    // 執行緒池所使用的緩衝佇列大小
    private final static int WORK_QUEUE_SIZE = 50;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        factory = beanFactory;
    }

    /**
     * 用於儲存在佇列中的訂單,防止重複提交,在真實場景中,可用redis代替 驗證重複
     */
    Map<String, Object> cacheMap = new ConcurrentHashMap<>();


    /**
     * 訂單的緩衝佇列,當執行緒池滿了,則將訂單存入到此緩衝佇列
     */
    Queue<Object> msgQueue = new LinkedBlockingQueue<Object>();


    /**
     * 當執行緒池的容量滿了,執行下面程式碼,將訂單存入到緩衝佇列
     */
    final RejectedExecutionHandler handler = new RejectedExecutionHandler() {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            //訂單加入到緩衝佇列
            msgQueue.offer(((BusinessThread) r).getAcceptStr());
            System.out.println("系統任務太忙了,把此訂單交給(排程執行緒池)逐一處理,訂單號:" + ((BusinessThread) r).getAcceptStr());
        }
    };


    /**建立執行緒池*/
    final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new ArrayBlockingQueue(WORK_QUEUE_SIZE), this.handler);


    /**將任務加入訂單執行緒池*/
    public void addOrders(String orderId){
        System.out.println("此訂單準備新增到執行緒池,訂單號:" + orderId);
        //驗證當前進入的訂單是否已經存在
        if (cacheMap.get(orderId) == null) {
            cacheMap.put(orderId, new Object());
            BusinessThread businessThread = new BusinessThread(orderId);
            threadPool.execute(businessThread);
        }
    }

    /**
     * 執行緒池的定時任務----> 稱為(排程執行緒池)。此執行緒池支援 定時以及週期性執行任務的需求。
     */
    final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);


    /**
     * 檢查(排程執行緒池),每秒執行一次,檢視訂單的緩衝佇列是否有 訂單記錄,則重新加入到執行緒池
     */
    final ScheduledFuture scheduledFuture = scheduler.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            //判斷緩衝佇列是否存在記錄
            if(!msgQueue.isEmpty()){
                //當執行緒池的佇列容量少於WORK_QUEUE_SIZE,則開始把緩衝佇列的訂單 加入到 執行緒池
                if (threadPool.getQueue().size() < WORK_QUEUE_SIZE) {
                    String orderId = (String) msgQueue.poll();
                    BusinessThread businessThread = new BusinessThread(orderId);
                    threadPool.execute(businessThread);
                    System.out.println("(排程執行緒池)緩衝隊列出現訂單業務,重新新增到執行緒池,訂單號:"+orderId);
                }
            }
        }
    }, 0, 1, TimeUnit.SECONDS);


    /**獲取訊息緩衝佇列*/
    public Queue<Object> getMsgQueue() {
        return msgQueue;
    }

    /**終止訂單執行緒池+排程執行緒池*/
    public void shutdown() {
        //true表示如果定時任務在執行,立即中止,false則等待任務結束後再停止
        System.out.println("終止訂單執行緒池+排程執行緒池:"+scheduledFuture.cancel(false));
        scheduler.shutdown();
        threadPool.shutdown();

    }
}

 

4、TestController.java

package com.cn.commodity.controller;

import com.cn.commodity.studyTest.TestThreadPoolManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Queue;
import java.util.UUID;


@RestController
public class TestController {

    @Autowired
    TestThreadPoolManager testThreadPoolManager;

    /**
     * 測試模擬下單請求 入口
     * @param id
     * @return
     */
    @GetMapping("/start/{id}")
    public String start(@PathVariable Long id) {
        //模擬的隨機數
        String orderNo = System.currentTimeMillis() + UUID.randomUUID().toString();

        testThreadPoolManager.addOrders(orderNo);

        return "Test ThreadPoolExecutor start";
    }

    /**
     * 停止服務
     * @param id
     * @return
     */
    @GetMapping("/end/{id}")
    public String end(@PathVariable Long id) {

        testThreadPoolManager.shutdown();

        Queue q = testThreadPoolManager.getMsgQueue();
        System.out.println("關閉了執行緒服務,還有未處理的資訊條數:" + q.size());
        return "Test ThreadPoolExecutor start";
    }
}

 

5、使用Jmeter測試,下載地址為:https://jmeter.apache.org/download_jmeter.cgi,下載完成後,解壓點選bin/下面的ApacheJMeter.jar檔案,就會出現介面,啟動springboot,按以下配置,就可以執行,模擬高併發。