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.mzph.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…