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角色进行高情商…

[学习笔记]刘知远团队大模型技术与交叉应用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 种不同的摩天大楼和建筑物。• 其中每个…

【2023 我的编程之旅】

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

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

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

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

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

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

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

Arm LDM和STM的寻址方式

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

LeetCode讲解篇之2280. 表示一个折线图的最少线段数

文章目录 题目描述题解思路题解代码 题目描述 题解思路 折线图中如果连续的线段共线,那么我们可以可以将其合并成一条线段 首先将坐标点按照横坐标升序排序 然后遍历数组 我们可以通过计算前一个线段的斜率和当前线段的斜率来判断是否共线 如果二者相等&#x…

Python之字符串中常用的方法

1. 去掉空格和特殊符号 name " abcdefgeyameng " name1 name.strip() # 并不会在原来的字符串上操作,返回一个去除了两边空白的字符串 print(name1, len(name1), name, len(name)) # abcdefgeyameng 14 abcdefgeyameng 17 # 去掉左边的空格和换行符 name2 n…

测试SpringBoot的时候报错mapper未装载的解决方案:

1.报错信息和截图: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name com.tang.testspringboot.TestSpringBootApplicationTests: Unsatisfied dependency expressed through field mapper: No qualifying bean o…

Python3.10安装教程

Python3.10安装 Python的安装按照下面几步进行即可,比较简单。 下载Python安装文件,打开Python的下载页面,我这里选择安装的版本是3.10.11,根据自己电脑版本选择对应安装包 安装包下载完毕后,按照步骤开始安装。选择…

620基于51单片机的密码锁设计[Proteus仿真]

620基于51单片机的密码锁设计[proteus仿真] 密码锁设计这个题目算是课 程设计和毕业设计中常见的题目了,本期是一个基于51单片机的密码锁设计 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】,赞赏任意文章 2¥,私信…

this.setState的注意事项

目录 1、this.setState的注意事项 2、是什么造成了this.setState()的不同步? 3、 那this.setState()什么时候同步,什么时候不同步? 3.1 经过React包装的onClick点击事件() 3.2 没经过React包装的 原生点击事件 …

嘘……快进来!这儿有最新版Microsoft照片程序的安装秘籍!(附安装引导程序下载)

网管小贾 / sysadm.cc 最近啊有不少小伙伴向我反馈,自个的 Windows 10 系统里边居然没有 Microsoft 照片 程序。 我觉得有点不可思议,为啥呢,因为他们的电脑是新买的! 你看哈,系统是 22H2 最新版,安装日期…

vscode打开c_cpp_properties.json文件的一种方式

步骤一 点击win32 步骤二 点击json 自动生成了

鸿蒙Harmony-线性布局(Row/Column)详解

人生的下半场,做个简单的人,少与人纠缠,多看大自然,在路上见世界,在途中寻自己。往后余生唯愿开心健康,至于其他,随缘就好! 目录 一,定义 二,基本概念 三&am…

如何使用“通义听悟”提高工作和学习效率

如何使用通义听悟提高工作和学习效率 通义听悟是一款利用人工智能技术,自动为音频和视频内容提供转写、翻译、总结、检索等功能的在线工具。它可以在会议、学习、访谈、培训等场景下,帮助您记录、阅读、整理、复习音视频信息,成为您的工作和…