線程池與緩存隊列實現的異步線程管理器應用ThreadPoolManager 源碼

業務場景

當系統A不關心繫統B執行的結果時,建議使用異步多線程的形式通知B系統處理,以下多線程的案例就是使用線程池和隊列的完成異步通知B系統的處理,廢話不多說,上代碼:

源碼:


/**
 * com.hshc.threadpool.ThreadPoolManager.java
 * Copyright 2017 Lifangyu, Inc. All rights reserved.
 * PROPRIETARY/CONFIDENTIAL.Use is subject to license terms.
 */
package com.hshc.threadpool;

import lombok.extern.slf4j.Slf4j;

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

/**
 * Desc:線程池管理器
 *
 * @author lifangyu
 * @date 2017/12/8.
 */
@Slf4j
public class ThreadPoolManager {

private static ThreadPoolManager instance;

/**
 * 線程池維護線程的最少數量
 */
private static int COREPOOLSIZE = 4;

/**
 * 線程池維護線程的最大數量
 */
private static int MAXPOOLSIZE = 10;

/**
 * 線程池維護線程所允許的空閒時間
 */
private static int KEEPALIVETIME = 0;

/**
 * 線程池所使用的緩衝隊列大小
 */
private static int WORKQUEUESIZE = 10;

/**
 * 消息緩衝隊列
 */
Queue<T> msgQueue = new LinkedList<>();


/**
 * 非單例帶參實例,重新創建一個實例[不推薦是使用]
 *
 * @param corepoolsize
 * @param maxpoolsize
 * @param keepalivetime
 * @param workqueuesize
 * @return ThreadPoolManager
 * @author lifangyu
 */
public static ThreadPoolManager newInstance(int corepoolsize, int maxpoolsize, int keepalivetime, int workqueuesize) {
    COREPOOLSIZE = corepoolsize;
    MAXPOOLSIZE = maxpoolsize;
    KEEPALIVETIME = keepalivetime;
    WORKQUEUESIZE = workqueuesize;
    instance = new ThreadPoolManager();
    return instance;
}

/**
 * 單例模式[推薦使用]
 *
 * @return ThreadPoolManager
 * @author lifangyu
 */
public static ThreadPoolManager getInstance() {
    if (instance == null) {
        synchronized (new Object()) {
            if (instance == null) {
                instance = new ThreadPoolManager();
            }
        }
    }
    return instance;
}


/**
 * 訪問消息緩存的調度線程[很重要]
 * 查看是否有待定請求,如果有,則創建一個新的AccessDBThread,並添加到線程池中
 */
final Runnable accessBufferThread = new Runnable() {
    @Override
    public void run() {
        if (hasMoreAcquire()) {
            T vo = (T) msgQueue.poll();
            Runnable task = new CallBackThread(vo);
            threadPool.execute(task);
        }
    }
};

final RejectedExecutionHandler handler = new RejectedExecutionHandler() {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        log.info("線程ID:{} execute thread [{}]消息放入隊列中重新等待執行", Thread.currentThread().getId(), ((CallBackThread) r).getVo().toString());
        msgQueue.offer(((CallBackThread<T>) r).getVo());
    }
};

/**
 * 管理數據庫訪問的線程池
 */
@SuppressWarnings({"rawtypes", "unchecked"})
final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(COREPOOLSIZE, MAXPOOLSIZE, KEEPALIVETIME,
        TimeUnit.SECONDS, new ArrayBlockingQueue(WORKQUEUESIZE), this.handler);

/**
 * 調度線程池
 */
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(100);

@SuppressWarnings("rawtypes")
final ScheduledFuture taskHandler = scheduler.scheduleAtFixedRate(accessBufferThread, 0, 1, TimeUnit.SECONDS);

private boolean hasMoreAcquire() {
    return !msgQueue.isEmpty();
}

public void noticeCallBack(String url,T vo) {
    Runnable task = new CallBackThread<T>(url,vo);
    threadPool.execute(task);
}

}


/**
* com.hshc.threadpool.CallBackThread.java
* Copyright 2017 Lifangyu, Inc. All rights reserved.
* HuaShengHaoChe PROPRIETARY/CONFIDENTIAL.Use is subject to license terms.
*/
package com.hshc.threadpool;

import com.hshc.common.utils.PropertiesUtil;
import com.hshc.common.utils.RestHttpUtil;
import com.hshc.wh.eas.domain.EasVoucherInstorageRequestVo;
import com.hshc.wh.eas.domain.EasVoucherMaterialRequestVo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
* Desc:TODO
*
* @author lifangyu
* @date 2017/12/8.
*/
@Slf4j
@Data
public class CallBackThread implements Runnable {

private String url;

private T vo;

public CallBackThread(T vo) {
    if (vo instanceof EasVoucherMaterialRequestVo) {
        this.url = PropertiesUtil.getConfigValueByKey("hshc.whapi.eas.material.url");

    } else if (vo instanceof EasVoucherInstorageRequestVo) {
        this.url = PropertiesUtil.getConfigValueByKey("hshc.whapi.eas.purchase.url");
    }
    log.info("CallBackThread.url:{}", url);
    this.vo = vo;
}

public CallBackThread(String url, T vo) {
    this.url = url;
    this.vo = vo;
}

@Override
public void run() {
    log.info("線程ID:{} execute callbackFeignClient.recharge start [url:{},param:{}] ", Thread.currentThread().getId(), url, vo.toString());
    // 需要異步執行的業務邏輯實現
    String result = RestHttpUtil.sendPost(url, vo);
    log.info("線程ID:{} execute callbackFeignClient.recharge end [result:{}] ", Thread.currentThread().getId(), vo.toString(), result);
}

}

說明

1.使用的jar:lombok;
2.消息緩存隊列很重要:Queue<T> msgQueue,如果由於資源競爭線程執行失敗,會進入到msgQueue緩存隊列中,在任務執行完後會檢查對列中是否有消息,有的話會再次執行不會有丟失的信息,可以通過本地大量數據多起幾個實例驗證此現象.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章