記錄一次日常開發中基於阻塞佇列的生產者和消費者模型

餘良94發表於2019-03-05
  • 在產品的開發中遇到一個業務場景,產品客戶端需要記錄對客戶端的每條請求並上報到產品後臺中心端。原來的程式碼邏輯是獲取到請求流量直接傳送給中心端,簡單粗暴。經過測試,如果客戶端在檢測高併發系統時效率大大降低,鑑於此處是一個典型的生產者消費者模式,考慮用阻塞佇列做快取,下面貼程式碼:

**

 流量快取阻塞佇列(選用LinkedBlockingQueque,設定大小為1000)
  private static  BlockingQueue<Mirror> cacheQueue = new LinkedBlockingQueue<Mirror> (1000);


 消費者:
/**
 *  客戶端初始化時呼叫
 */
public static void initMirrorSender() throws Exception {
        //此處也可使用執行緒池,因為是常駐執行緒,所以區別不大
        Thread senderThread = new Thread(new Runnable() {
        List<Mirror> mirrorList;
            Mirror mirror;
            @Override
            public void run() {
                while (true) {
                    //每次取流量時如果當前佇列裡無元素,則block
                    mirror = cacheQueue.take();
				    mirrorList.add(mirror);
					
					//保證每次傳送最大不超過200條
				    while(mirrorList.size<200 && (mirror = cacheQueue.poll()) != null ){
				           mirrorList.add(mirror);
				    }  
                    
                    try{
                            //向中心端傳送流量
                   			 HttpUtil.sendPost(url,  mirrorList);
                    }catch(Throwable t){
                           LOGGER.error(t);
                    }
                    
                    try {
                        //預設200毫秒從佇列裡取一次
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        LOGGER.error(e);
                    }
                    continue;
                }

            }
        });
        thread.start();
    }

生產者

         public static void mirrorGenerator(Mirror mirror){
         			//此處省略對mirror的引數校驗
         			。。。。
					if(cacheQueue.offer(mirror)){
							Logger.info("Cache successfully!")
					}else{
					     	Logger.info("Cache Failed!");
					}
         }

通過優化,大大 減少了http請求互動,挺高了效能

相關文章