Java高并發之BlockingQueue

使用BlockingQueue隊列處理高并發下的日志

前言碎語

當系統流量負載比較高時,業務日志的寫入操作也要納入系統性能考量之內,如若處理不當,將影響系統的正常業務操作,之前寫過一篇《spring boot通過MQ消費log4j2的日志》的博文,采用了RabbitMQ消息中間件來存儲抗高并發下的日志,因為引入了中間件,操作使用起來可能沒那么簡便,今天分享使用多線程消費阻塞隊列的方式來處理我們的海量日志

waht阻塞隊列?

阻塞隊列(BlockingQueue)是區別于普通隊列多了兩個附加操作的線程安全的隊列。這兩個附加的操作是:在隊列為空時,獲取元素的線程會等待隊列變為非空。當隊列滿時,存儲元素的線程會等待隊列可用。阻塞隊列常用于生產者和消費者的場景,生產者是往隊列里添加元素的線程,消費者是從隊列里拿元素的線程。阻塞隊列就是生產者存放元素的容器,而消費者也只從容器里拿元素。

1.聲明存儲固定消息的隊列

/*** Created by kl on 2017/3/20.* Content :銷售操作日志隊列*/
public class SalesLogQueue{//隊列大小public static final int QUEUE_MAX_SIZE    = 1000;private static SalesLogQueue alarmMessageQueue = new SalesLogQueue();//阻塞隊列private BlockingQueueblockingQueue = new LinkedBlockingQueue<>(QUEUE_MAX_SIZE);private SalesLogQueue(){}public static SalesLogQueue getInstance() {return alarmMessageQueue;}/*** 消息入隊* @param salesLog* @return*/public boolean push(SalesLog salesLog) {return this.blockingQueue.add(salesLog);//隊列滿了就拋出異常,不阻塞}/*** 消息出隊* @return*/public SalesLog poll() {SalesLog result = null;try {result = this.blockingQueue.take();} catch (InterruptedException e) {e.printStackTrace();}return result;}/*** 獲取隊列大小* @return*/public int size() {return this.blockingQueue.size();}
}

ps:因為業務原因,采用add的方式入隊,隊列滿了就拋異常,不阻塞

2.消息入隊

消息入隊可以在任何需要保存日志的地方操作,如aop統一攔截日志處理,filter過濾請求日志處理,或者耦合的業務日志,記住,不阻塞入隊操作,不然將影響正常的業務操作,如下為filter統一處理請求日志:

/*** Created by kl on 2017/3/20.* Content :訪問請求攔截,保存操作日志*/
public class SalesLogFilter implements Filter {private RoleResourceService resourceService;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {ServletContext context = filterConfig.getServletContext();ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);resourceService = ctx.getBean(RoleResourceService.class);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {try {HttpServletRequest request = (HttpServletRequest) servletRequest;String requestUrl = request.getRequestURI();String requestType=request.getMethod();String ipAddress = HttpClientUtil.getIpAddr(request);Map resource=resourceService.getResource();String context=resource.get(requestUrl);//動態url正則匹配if(StringUtil.isNull(context)){for(Map.Entry entry:resource.entrySet()){String resourceUrl= entry.getKey();if(requestUrl.matches(resourceUrl)){context=entry.getValue();break;}}}SalesLog log=new SalesLog();log.setCreateDate(new Timestamp(System.currentTimeMillis()));log.setContext(context);log.setOperateUser(UserTokenUtil.currentUser.get().get("realname"));log.setRequestIp(ipAddress);log.setRequestUrl(requestUrl);log.setRequestType(requestType);SalesLogQueue.getInstance().push(log);}catch (Exception e){e.printStackTrace();}filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {}
}

3.消息出隊被消費

BlockingQueue是線程安全的,所以可以放心的在多個線程中去處理隊列中的消息,如下代碼聲明了一個兩個大小的固定線程池,并添加了兩個線程去處理隊列中的消息

?

/*** Created by kl on 2017/3/20.* Content :啟動消費操作日志隊列的線程*/
@Component
public class ConsumeSalesLogQueue {@AutowiredSalesLogService salesLogService;@PostConstructpublic void startrtThread() {ExecutorService e = Executors.newFixedThreadPool(2);//兩個大小的固定線程池e.submit(new PollSalesLog(salesLogService));e.submit(new PollSalesLog(salesLogService));}class PollSalesLog implements Runnable {SalesLogService salesLogService;public PollSalesLog(SalesLogService salesLogService) {this.salesLogService = salesLogService;}@Overridepublic void run() {while (true) {try {SalesLog salesLog = SalesLogQueue.getInstance().poll();if(salesLog!=null){salesLogService.saveSalesLog(salesLog);}} catch (Exception e) {e.printStackTrace();}}}}
}

參考博文如下,對BlockingQueue隊列更多了解,可讀一讀如下的博文:

  • ??http://blog.csdn.net/vernonzheng/article/details/8247564
  • ? http://www.infoq.com/cn/articles/java-blocking-queue
  • ??http://wsmajunfeng.iteye.com/blog/1629354

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386779.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386779.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386779.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python中文字符串轉list

本文主要記錄了將中文字符串轉換為list的過程&#xff0c;其中我們使用了keras preprocessing中的text_to_word_sequence方法。這個方法是完全適配中文的。需要注意的是&#xff0c;中文語料一般字符之間是沒有空格分割的&#xff0c;這與英文是不同的。如下所示&#xff0c;如…

IP通信基礎回顧2(第三周)

1.TCP報文 序號字段占4個字節。TCP連接中傳送的數據流中每一個字節都編上一個序號。序號字段的值則是本報文段所發送的數據第一個字節的序號。 確認序號占4個字節。是期望收到的對方的下一個報文段字節胡序號。首部長度占4個字節。指出TCP首部長度在20-60字節之間&#xff0c;所…

ThreadPoolExecutor線程池 + Queue隊列

1&#xff1a;BlockingQueue繼承關系 java.util.concurrent 包里的 BlockingQueue是一個接口&#xff0c; 繼承Queue接口&#xff0c;Queue接口繼承 Collection BlockingQueue----->Queue-->Collection 圖&#xff1a; 隊列的特點是&#xff1a;先進先出&#xff08;FIFO…

python list pop方法

通過使用pop方法可以直接刪除列表中的某一個對應元素并返回該元素值 s [a, b, c, d] # 通過使用pop方法可以移除list中的一個元素并返回它的值 result s.pop(1) print(result) print(s)結果如下 b [a, c, d]

linux基礎文件管理軟硬鏈接

一、文件系統的基本結構 1、文件和目錄被組成一個單根倒置樹目錄結構 2、文件系統從根目錄下開始&#xff0c;用“/”表示 3、根文件系統&#xff08;rootfs&#xff09;&#xff1a;root filesystem文件名區分大小寫 4、以 . 開頭的文件為隱藏文件 5、路徑用/隔離 6文件有兩類…

mybatis動態更新xml文件后熱部署,不重啟應用的方法

mybatis應用程序&#xff0c;由于是半自動化的sql, 有大量的sql是在xml文件中配置的&#xff0c;而在開發程序的過程中&#xff0c;通常需要邊寫sql變調試應用。但在默認情況下&#xff0c;xml文件里配置的sql語句是被放入到緩存中去了&#xff0c;每次更改有sql語句的xml文件&…

Leetcode 反轉字符串 II python解法

題干&#xff1a; 給定一個字符串 s 和一個整數 k&#xff0c;從字符串開頭算起&#xff0c;每計數至 2k 個字符&#xff0c;就反轉這 2k 字符中的前 k 個字符。 如果剩余字符少于 k 個&#xff0c;則將剩余字符全部反轉。 如果剩余字符小于 2k 但大于或等于 k 個&#xff0c;…

下拉插件 (帶搜索) Bootstrap-select 從后臺獲取數據填充到select的 option中 用法詳解...

今天收到了客戶的需求&#xff0c;要求在新增停車場ID的時候要從數據庫查出來對應的停車場名稱然后顯示在界面上。保存的時候按照停車場ID進行保存。 自己首先把后臺的部分寫完了&#xff0c;測試了接口數據。成功的拿到了ajax數據。 接下來&#xff0c;自己用了select下拉標簽…

pytorch tensorboard基本用法整理

from torch.utils.tensorboard import SummaryWriterif __name__ __main__:aa SummaryWriter(logs) # 創建保存了summarywriter的log目錄for i in range(100):aa.add_scalar(y x, i, i) # 后兩個參數先y軸后x軸 x軸往往是global step y軸用于輸出loss或者其他需要觀察的變量…

php 支付寶付款接口測試

詳細去這里&#xff1a;https://blog.csdn.net/suprezheng/article/details/84931225 轉載于:https://www.cnblogs.com/LF-place/p/10898357.html

spring boot mybatis攔截器

mybaits攔截器 package com.chinamobile.scm.masterdata.interceptor;import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apach…

Linux自有服務(2)-Linux從入門到精通第六天(非原創)

文章大綱 一、設置主機名二、chkconfig三、ntp服務四、防火墻服務五、rpm管理&#xff08;重點&#xff09;六、cron/crontab計劃任務&#xff08;重點&#xff09;七、學習資料下載八、參考文章 自有服務&#xff0c;即不需要用戶獨立去安裝的軟件的服務&#xff0c;而是當系統…

Spring 事務 以及攔截器的前后關系實驗 Mybatis 日志攔截

背景&#xff1a;當一個線程中&#xff0c;如果需要攔截所有當SQL日志&#xff0c;然后統一發送到一個同步器&#xff0c;就可以實現多個數據庫實現同步主庫&#xff0c;在進行紅綠上線&#xff0c;或者灰度部署時候&#xff0c;可以實現生產庫與測試庫實時同步&#xff0c;從而…

四級翻譯常用詞匯

ancient 古老的&#xff1b;古代的       achieve 獲得 v attract 吸引 v            achievement 成就 n attractive 吸引人的          advanced 先進的 account for 對....負有責任&#xff1b;占比   approach 接近&#xff1b;處理&#…

一般攔截器 serviceImpl部分

一般攔截器 serviceImpl部分 package com.chinamobile.scm.masterdata.interceptor;import com.chinamobile.framework.common.context.InvokeTracer; import com.chinamobile.framework.common.context.RequestContext; import com.chinamobile.framework.utils.CollectionUt…

營銷-營銷方式:營銷方式

ylbtech-營銷-營銷方式&#xff1a;營銷方式營銷方式是指營銷過程中所有可以使用的方法。包括服務營銷、體驗營銷、知識營銷、情感營銷、教育營銷、差異化營銷、直銷、網絡營銷等。要有好的營銷方式首先要創造行之有效的營銷工具。但這并不意味著要把預算的75%都花在印制宣傳資…

以后可能用到的一些OQL

Visual VM對OQL的支持 上面我們學會了如何查看堆內存快照&#xff0c;但是&#xff0c;堆內存快照十分龐大&#xff0c;快照中的類數量也很多。Visual VM提供了對OQL&#xff08;對象查詢語言&#xff09;的支持&#xff0c;以便于開發人員在龐大的堆內存數據中&#xff0c;快…

leetcode1041困于環中的機器人

題目如下&#xff0c;一道簡單的模擬 在無限的平面上&#xff0c;機器人最初位于 (0, 0) 處&#xff0c;面朝北方。機器人可以接受下列三條指令之一&#xff1a;"G"&#xff1a;直走 1 個單位 "L"&#xff1a;左轉 90 度 "R"&#xff1a;右轉 90…

一個拆分使用的存儲過程例子

set serverout on declare var_tmp varchar2(4000) :; var_element varchar2(4000) :; n_length Number : length(\/); begin values_array : VARCHAR_ARRAY(); -- 初始化數組 for i in (select * from sapsr3.zmdm_mthdr where zmtpre in(6200001…

python的pwntools工具的日常使用

1.安裝 操作系統&#xff1a; ubuntu16.04 環境準備&#xff1a; pythonpiplibssl-devlibffi-dev pwntools安裝&#xff1a; sudo apt-get install libffi-devsudo apt-get install libssl-devsudo apt-get install pythonsudo apt-get install python-pipsudo pip install pwn…