多線程進行同步數據

開發中會有場景需要對接第三方系統.第三方系統往往會提供一箇中間庫,然後我們系統讀取中間庫的數據,然後經過一系列的邏輯,把數據存到自己系統中. 在這裏分享一種通過生產者,消費者模式進行數據同步,接近實時

主要思路: 一個生產者線程, 實時去中間庫查詢沒有同步的數據.多個消費者,消費生產者生產的數據

                 1.一個生產者線程, 實時去中間庫查詢沒有同步的數據

                 2.使用消費者對生產者生產的數據進行同步

                 3.記錄下處理完成/處理失敗的同步記錄

 

/**
 * 同步中間庫生產者.從中間庫中查詢數據
 */
public class Producer implements Runnable {

    private OwnerMiddleQueryService queryService;//查詢中間庫Service,可考慮抽成接口
    private LinkedBlockingQueue<Runnable> consumers;//消費者隊列
    private ThreadPoolExecutor executor;//線程池


    public Producer(OwnerMiddleQueryService queryService, LinkedBlockingQueue<Runnable>
            consumers, ThreadPoolExecutor executor) {
        this.queryService = queryService;
        this.consumers = consumers;
        this.executor = executor;
    }

    @Override
    public void run() {
        while (true){
            List<OwnerMiddle> datas =  queryService.selectCount(50);
            if(datas != null && !datas.isEmpty()){
                try {
                    Consumer consumer = (Consumer) consumers.take();//從隊列中取出一個消費者
                    queryService.updateStatus(datas);//更改狀態字段或記錄操作記錄
                    consumer.setDatas(datas);//查詢出的數據給到消費者中
                    executor.execute(consumer);//執行消費者操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    queryService.updateStatus(datas);//記錄下同步失敗的記錄

                }
            }else {
                try {
                    TimeUnit.SECONDS.sleep(3);//防止一直查詢空的結果
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
/**
 * 同步中間庫消費者.消費生產者的數據
 */
public class Consumer implements Runnable{

    private List<OwnerMiddle> datas;//待同步數據
    private OwnerMiddleDealService ownerMiddleDealService;//用於同步數據的Service
    private LinkedBlockingQueue<Runnable> consumers;//消費者隊列

    public Consumer(OwnerMiddleDealService ownerMiddleDealService, LinkedBlockingQueue<Runnable>
            consumers) {
        this.ownerMiddleDealService = ownerMiddleDealService;
        this.consumers = consumers;
    }

    @Override
    public void run() {
        try{
            ownerMiddleDealService.dealData(datas);//進行同步數據:把數據插入到自己系統的庫中,並記錄下同步記錄
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                consumers.put(this);//消費者用完後放回隊列
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public List<OwnerMiddle> getDatas() {
        return datas;
    }

    public void setDatas(List<OwnerMiddle> datas) {
        this.datas = datas;
    }
}

由於我們需要在系統啓動時即開啓該線程.故我們監聽ContextRefreshedEvent事件進行觸發.注意, 不能監聽ContextStartedEvent事件,該事件是在所有的bean初始化之前的.這樣我們一些Service,Mapper對象都會無法注入.

@Component
public class SyncMiddleComponent implements ApplicationListener<ContextRefreshedEvent> {

    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20)); //線程池
    private LinkedBlockingQueue<Runnable> runnables = new LinkedBlockingQueue<>(10);//任務隊列


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        OwnerMiddleQueryService middleQueryService = new OwnerMiddleQueryService();
        OwnerMiddleDealService middleDealService = new OwnerMiddleDealService();
        for (int i = 0; i < 10; i++) {
            //10個消費者
            try {
                runnables.put(new Consumer(middleDealService,runnables));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Producer producer = new Producer(middleQueryService, runnables, threadPoolExecutor);
        new Thread(producer).start();//開啓生產者線程
    }
}

OwnerMiddleDealService  和 OwnerMiddleQueryService的方法的實現都是些業務邏輯.主要邏輯已標明在註釋中.具體的邏輯則要根據系統的業務進行編碼.

另外值得注意的是.由於在線程中是不能直接注入Spring管理的bean的.因爲線程沒有被Spring管理.此處可以自定義一個工具類,實現 ApplicationContextAware進行手動獲取bean.可在類的構造器中進行獲取.

具體可以參考:https://blog.csdn.net/fubo1990/article/details/79648766

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章