ArrayBlockingQueue的使用

异步日志打印模型概述

在高并发、高流量并且响应时间要求比较小的系统中同步打印日志已经满足不了需求了,这是因为打印日志本身是需要写磁盘的,写磁盘的操作会暂时阻塞调用打印日志的业务线程,这会造成调用线程的rt增加。

如图所示为同步日志打印模型。

在这里插入图片描述
同步日志打印模型的缺点是将日志写入磁盘的操作是业务线程同步调用完成的,那么是否可以让业务线程把要打印的日志任务放入一个队列后直接返回,然后使用一个线程专门负责从队列中获取日志任务并将其写入磁盘呢?这样的话,业务线程打印日志的耗时就仅仅是把日志任务放入队列的耗时了,其实这就是logback提供的异步日志打印模型要做的事,具体如图所示。

在这里插入图片描述
其实logback的异步日志模型是一个多生产者-单消费者模型,其通过使用队列把同步日志打印转换为了异步,业务线程只需要通过调用异步appender把日志任务放入日志队列,而日志线程则负责使用同步的appender进行具体的日志打印。

日志打印线程只需要负责生产日志并将其放入队列,而不需要关心消费线程何时把日志具体写入磁盘。

异步日志与具体实现

异步日志

在这里插入图片描述
AsyncAppender 继承自 AsyncAppenderBase,其中后者具体实现了异步日志模型的主要功能,前者只是重写了其中的一些方法。

由该图可知,logback 中的异步日志队列是一个阻塞队列,其实就是有界阻塞队列ArrayBlockingQueue,其中 queueSize表示有界队列的元素个数,默认为256个。

worker是个线程,也就是异步日志打印模型中的单消费者线程。

aai 是一个 appender的装饰器,里面存放同步日志的appender,其中 appenderCount 记录 aai里面附加的同步 appender 的个数。

neverBlock用来指示当日志队列满时是否阻塞打印日志的线程。

discardingThreshold 是一个阈值,当日志队列里面的空闲元素个数小于该值时,新来的某些级别的日志会被直接丢弃,下面会具体讲。

首先我们来看何时创建日志队列,以及何时 启动消费线程,这需要看AsyncAppenderBase 的 start方法。该方法在解析完配置 AsyncAppenderBase 的 xml 的节点元素后被调用。

在这里插入图片描述
由以上代码可知,logback使用的是有界队列 ArrayBlockingQueue,之所以使用有界队列是考虑内存溢出问题。

在高并发下写日志的QPS会很高,如果设置为无界队列,队列本身会占用很大的内存,很可能会造成OOM。

这里消费日志队列的 worker线程被设置为守护线程,这意味着当主线程运行结束并且当前没有用户线程时,该worker线程会随着JVM的退出而终止,而不管日志队列里面是否还有日志任务未被处理。

另外,这里设置了线程的名称,这是个很好的习惯,因为在查找问题时会很有帮助,根据线程名字就可以定位线程。

既然是有界队列,那么肯定需要考虑队列满的问题,是丢弃老的日志任务,还是阻塞日志打印线程直到队列有空余元素呢?要回答这个问题,我们需要看看具体进行日志打印的AsyncAppenderBase的append方法。

在这里插入图片描述
其中代码(5)调用了AsyncAppender重写的isDiscardable方法,该方法的具体内容为
在这里插入图片描述
结合代码(5)和代码(7)可知,如果当前日志的级别小于等于INFO_INT并且当前队列的剩余容量小于discardingThreshold则会直接丢弃这些日志任务。

下面看具体代码(6)中的put方法。
在这里插入图片描述
如果neverBlock被设置为false(默认为false)则会调用阻塞队列的put方法,而put是阻塞的,也就是说如果当前队列满,则在调用put方法向队列放入一个元素时调用线程会被阻塞直到队列有空余空间。

这里可以看下put方法的实现。

在这里插入图片描述
这里有必要解释下代码(9),当日志队列满时put方法会调用await()方法阻塞当前线程,而如果其他线程中断了该线程,那么该线程会抛出InterruptedException异常,并且当前的日志任务就会被丢弃。

在logback-classic的1.2.3版本中,则添加了不对中断进行响应的方法。

在这里插入图片描述
如果当前日志打印线程在调用blockingQueue.put时被其他线程中断,则只是记录中断标志,然后继续循环调用blockingQueue.put,尝试把日志任务放入日志队列。

新版本的这个实现通过使用循环保证了即使当前线程被中断,日志任务最终也会被放入日志队列。

如果neverBlock被设置为true则会调用阻塞队列的offer方法,而该方法是非阻塞的,所以如果当前队列满,则会直接返回,也就是丢弃当前日志任务。这里回顾下offer方法的实现。

在这里插入图片描述
最后来看addAppender方法都做了什么。

在这里插入图片描述
由如上代码可知,一个异步appender只能绑定一个同步appender。这个appender会被放到AppenderAttachableImpl的appenderList列表里面。

到这里我们已经分析完了日志生产线程把日志任务放入日志队列的实现,下面一起来看消费线程是如何从队列里面消费日志任务并将其写入磁盘的。

由于消费线程是一个线程,所以就从worker的run方法开始。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/622176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WorkPlus领先企业即时通信软件,提升团队沟通效率的利器

在企业工作中,高效沟通是推动团队协作和工作效率的关键。而企业即时通信软件成为了实现高效沟通的利器。作为一款领先的企业即时通信软件,WorkPlus以其卓越的性能和独特的功能,提升团队沟通效率,助力企业实现高效协作。 为什么选择…

豆包ai介绍

豆包是字节跳动基于云雀模型开发的AI工具,具有强大的语言处理能力和广泛的应用场景,无论是在学习、工作、生活中,都能派上用场。 豆包可以帮助打工人和创作者提升效率,完成各种工作任务,又能扮演各类AI角色进行高情商…

win10安装electron卡住

切换镜像源,需要设置ELECTRON_MIRROR才行,win10操作如下: set ELECTRON_MIRRORhttp://npm.taobao.org/mirrors/electron/ npm install --save-dev electron

C++右值引用,右值引用与const引用的区别

1.右值与左值 左值:可以取地址的、有名字的变量,有持久性;右值:一般是不可寻址的常量,或在表达式求值过程中创建的无名临时对象,短暂性的。 2.右值引用 C11新增了另一种引用——右值引用。这种引用可指向…

[学习笔记]刘知远团队大模型技术与交叉应用L1-NLPBig Model Basics

本节主要介绍NLP和大模型的基础知识。提及了词表示如何从one-hot发展到Word Embedding。语言模型如何从N-gram发展成预训练语言模型PLMs。然后介绍了大模型在NLP任务上的表现,以及它遵循的基本范式。最后介绍了本课程需要用到的编程环境和GPU服务器。 一篇NLP方向的…

从零开始做题:逆向wdb_2018_2nd_easyfmt

1.题目信息 2.解题分析 格式化字符串漏洞 如何确定偏移 Do you know repeater? 输入AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p. 输出AAAA.0xffffd658.0x64.0xf7ffdc08.0xf7ffcd00.0xffffd77c.0x41414141.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252…

City Terrace Pack

“城市与露台资源包” 的主要特点:• 属于系列的一部分。• 极为逼真和现代化的城市。• 高度优化的低多边形和逼真资源。• 可用于 Oculus、GearVR、Vive、Daydream。• 可用于低端和高端移动设备。• 灵感来自于现代建筑和设计。• 36 种不同的摩天大楼和建筑物。• 其中每个…

【Windows 10 / 11】彻底卸载Microsoft Edge

彻底卸载Microsoft Edge的方法 第一种 打开C盘,定位到Edge安装目录,一般是“C:\Program Files (x86)\Microsoft\Edge\Application\”进入对应当前Edge版本号的文件夹,并进入“Installer”文件夹内找到“setup.exe”按下“shift”键并点击鼠标…

【ARM 嵌入式 编译系列 10.4 -- elf 文件各个段信息查看】

文章目录 elf 文件各个段信息查看 elf 文件各个段信息查看 在进行代码编译完成的时候,我们会经常见到下面信息, 这个是怎么实现的呢? text data bss dec hex filename11818 2120 5736 19674 4cda ra4m2.elf使用 arm-none-eab…

第九部分 使用函数 (二)

目录 一、字符串处理函数 1、subst 2、patsubst 3、strip 4、findstring 5、filter 6、filter-out 7、sort 8、word 9、wordlist 10、words 11、firstword 12、字符串函数实例 一、字符串处理函数 1、subst $(subst <from>,<to>,<text>) 名称…

【2023 我的编程之旅】

前言 转眼 2024 年都过去 14 天了。回顾 2023 有太多技术上的思考以及人生的感悟&#xff0c;接下来趁着 CSDN 官方活动&#xff0c;顺便记录下来。 技术的价值 与现在的年轻人一心只想搞钱不同&#xff0c;刚毕业的时候&#xff0c;我的梦想是进入一家有实力的科技企业&…

如何创建并格式化硬盘分区?

一般将新硬盘连接到计算机后&#xff0c;需先创建并格式化硬盘分区。否则在磁盘管理中会显示为“未分配空间”&#xff0c;并在文件资源管理器中不可见。那我们如何在硬盘上创建新分区&#xff0c;并对新分区进行格式化&#xff1f; 方法1. 通过命令提示符 首先&#xff0c;我…

两周掌握Vue3(三):全局组件、局部组件、Props

文章目录 一、全局组件1.创建全局组件2.在main.js中注册全局组件3.使用全局组件 二、局部组件1.创建局部组件2.在另一个组件中注册、使用局部组件 三、Props1.定义一个子组件2.定义一个父组件3.效果 代码仓库&#xff1a;跳转 本博客对应分支&#xff1a;03 一、全局组件 Vue…

四、C#高级特性(反射与序列化)

在C#中&#xff0c;反射&#xff08;Reflection&#xff09;和序列化&#xff08;Serialization&#xff09;是两个重要的高级特性&#xff0c;它们在程序设计和开发中有着广泛的应用。 反射&#xff08;Reflection&#xff09; 反射是.NET框架的一个重要特性&#xff0c;它允…

c语言之输出函数用法 putchar

putchar函数 putchar函数是c语言输出函数&#xff0c;但它只能输出单个字符&#xff0c;如果要输出字符串就不合适了。 应用举例 #include<stdio.h> int main() {putchar(a);putchar(4);putchar(\n);return 0: } 从上面代码可以看出&#xff0c;单字符必须用单引号’…

vue项目添加改变浏览器标签title的标题

第一步:在main.js文件里添加 Vue.directive(title,{inserted:function(el,binding{document.title el.dataset.title}) })第二步:在组件任意一位置添加 <template><div class""main v-title data-title"自定义首页标题"></div> </…

计算机缺失mfu140u.dll的5种解决方法,亲测有效

在计算机系统运行过程中&#xff0c;mfu140u.dll文件的丢失是一个较为常见的问题场景。这个动态链接库文件(mfu140u.dll)对于系统的正常运行具有关键作用&#xff0c;它的缺失可能导致相关应用程序无法启动或执行功能异常。具体来说&#xff0c;mfu140u.dll丢失的场景可能出现在…

原子的质量是由质子质量、中子质量、电子质量组成的吗?

问题描述&#xff1a;原子的质量是由质子质量、中子质量、电子质量组成的吗&#xff1f; 问题解答&#xff1a; 是的&#xff0c;原子的质量主要由构成原子的质子、中子和电子的质量组成。这三种基本粒子在原子中分别承担不同的角色&#xff1a; 质子&#xff08;Proton&…

操作系统复习 五、六章

操作系统复习 五、六章 文章目录 操作系统复习 五、六章第五章 并发性: 互斥和同步基本概念实现临界区互斥访问的基本方法信号量管程 第六章 并发性:死锁和饥饿死锁的概念死锁的处理策略死锁的预防死锁避免死锁的检测和接触饥饿、死锁、死循环的区别 第五章 并发性: 互斥和同步…

Arm LDM和STM的寻址方式

A32指令集中包含多数据传输指令LDM和STM&#xff0c;也就是单条指令可以传输多个寄存器的值与内存交互&#xff0c;这对于数据块传输以及寄存器的压入栈很有帮助。LDM和STM指令可分别用于实现堆栈的pop和push操作。对于堆栈操作&#xff0c;基寄存器通常是堆栈指针(SP)。 LDM和…