Log4J 日志的异步类解读(lAsyncAppender)
为什么80%的码农都做不了架构师?>>>
/*** The AsyncAppender lets users log events asynchronously.* <p/>* <p/>* The AsyncAppender will collect the events sent to it and then dispatch them* to all the appenders that are attached to it. You can attach multiple* appenders to an AsyncAppender.* </p>* <p/>* <p/>* The AsyncAppender uses a separate thread to serve the events in its buffer.* </p>* <p/>* <b>Important note:</b> The <code>AsyncAppender</code> can only be script* configured using the {@link org.apache.log4j.xml.DOMConfigurator}.* </p>** @author Ceki Gülcü* @author Curt Arnold* @since 0.9.1*/
//构造
/*** Create new instance.*/public AsyncAppender() {appenders = new AppenderAttachableImpl();//// only set for compatibilityaai = appenders;dispatcher =new Thread(new Dispatcher(this, buffer, discardMap, appenders));// It is the user's responsibility to close appenders before// exiting.dispatcher.setDaemon(true);// set the dispatcher priority to lowest possible value// dispatcher.setPriority(Thread.MIN_PRIORITY);dispatcher.setName("Dispatcher-" + dispatcher.getName());dispatcher.start();}
//构造 构造了一个叫despatcher的最低级别守护进程。
//其实唯一需要关注的方法就是append,我们看它怎么做异步append
/*** {@inheritDoc}*/public void append(final LoggingEvent event) {//// if dispatcher thread has died then// append subsequent events synchronously// See bug 23021// 如果dispatcher线程不在了,直接调用各个appender的同步写方法,确保日志的写入if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) {synchronized (appenders) {appenders.appendLoopOnAppenders(event);}return;}// Set the NDC and thread name for the calling thread as these// LoggingEvent fields were not set at event creation time.event.getNDC();event.getThreadName();// Get a copy of this thread's MDC.event.getMDCCopy();if (locationInfo) {event.getLocationInformation();}synchronized (buffer) { //这里将buffer资源对象当锁,可以想象到所有操作buffer的方法都必须做同步。while (true) {int previousSize = buffer.size();if (previousSize < bufferSize) {buffer.add(event);//// if buffer had been empty// signal all threads waiting on buffer// to check their conditions.//if (previousSize == 0) {buffer.notifyAll(); //notifyAll()方法是Object对象的方法,而不是Thread对象的方法。}break;}//// Following code is only reachable if buffer is full// 如果buffer写满了,才会走到下面的代码流程//// if blocking and thread is not already interrupted// and not the dispatcher then// wait for a buffer notificationboolean discard = true;if (blocking //buffer满就阻塞的标志位&& !Thread.interrupted()&& Thread.currentThread() != dispatcher) {try {buffer.wait(); //满了就等待把discard = false;} catch (InterruptedException e) {//// reset interrupt status so// calling code can see interrupt on// their next wait or sleep.Thread.currentThread().interrupt(); //这里处理interrupt的方法值得体会:)当然可以学会套用这个模板}}//// if blocking is false or thread has been interrupted// add event to discard map.//if (discard) { //如果没能成功进入wait(),放到丢弃消息map中保存String loggerName = event.getLoggerName();DiscardSummary summary = (DiscardSummary) discardMap.get(loggerName);if (summary == null) {summary = new DiscardSummary(event);discardMap.put(loggerName, summary);} else {summary.add(event);}break;}}}}
//这里出现了2个新的东西,dispatcher 和DiscardSummary,下面分析dispatcher线程的实现
/*** Event dispatcher.*/private static class Dispatcher implements Runnable {/*** Parent AsyncAppender.*/private final AsyncAppender parent;/*** Event buffer.*/private final List buffer;/*** Map of DiscardSummary keyed by logger name.*/private final Map discardMap;/*** Wrapped appenders.*/private final AppenderAttachableImpl appenders;/*** Create new instance of dispatcher.** @param parent parent AsyncAppender, may not be null.* @param buffer event buffer, may not be null.* @param discardMap discard map, may not be null.* @param appenders appenders, may not be null.*/public Dispatcher(final AsyncAppender parent, final List buffer, final Map discardMap,final AppenderAttachableImpl appenders) {this.parent = parent;this.buffer = buffer;this.appenders = appenders;this.discardMap = discardMap;}/*** {@inheritDoc}*/public void run() {boolean isActive = true;//// if interrupted (unlikely), end thread//try {//// loop until the AsyncAppender is closed.//while (isActive) {LoggingEvent[] events = null;//// extract pending events while synchronized// on buffer//synchronized (buffer) {int bufferSize = buffer.size();isActive = !parent.closed;while ((bufferSize == 0) && isActive) {buffer.wait();bufferSize = buffer.size();isActive = !parent.closed;}if (bufferSize > 0) {events = new LoggingEvent[bufferSize + discardMap.size()];buffer.toArray(events);//// add events due to buffer overflow//int index = bufferSize;for (Iterator iter = discardMap.values().iterator();iter.hasNext();) {events[index++] = ((DiscardSummary) iter.next()).createEvent();}//// clear buffer and discard map//buffer.clear();discardMap.clear();//// allow blocked appends to continuebuffer.notifyAll();}}//// process events after lock on buffer is released.//if (events != null) {for (int i = 0; i < events.length; i++) {synchronized (appenders) {appenders.appendLoopOnAppenders(events[i]);}}}}} catch (InterruptedException ex) {Thread.currentThread().interrupt();}}}
转载于:https://my.oschina.net/exit/blog/158289
Log4J 日志的异步类解读(lAsyncAppender)相关推荐
- log4j日志输出性能优化-缓存、异步
1.log4j已成为大型系统必不可少的一部分,log4j可以很方便的帮助我们在程序的任何位置输出所要打印的信息,便于我们对系统在调试阶段和正式运行阶段对问题分析和定位.由于日志级别的不同,对系统的性能 ...
- java自定义日志级别_自定义log4j日志级别
因为项目中需要输出一些特别的日志来做数据统计.如果开启log4j提供的INFO日志级别,每天生成的日志文件就会变得越来越大.这样就得写个定 时任务来删除这个文件.为了只输出所需的日志级别,唯有自己定义 ...
- linux日志文件存放目录,Log4j 日志文件Linux/Mac/Windows通用存放位置设置方法
log4j1/log4j2中category的配置以及log的输出位置(windows和linux通用的log输出位置) 一.场景和需求 假设我现在有3个独立的用project(暂时用maven关联起 ...
- Mybatis 的Log4j日志输出问题 - 以及有关日志的所有问题
转载自 Mybatis 的Log4j日志输出问题 - 以及有关日志的所有问题 使用Mybatis的时候,有些时候能输出(主要是指sql,参数,结果)日志.有些时候就不能. 无法输出日志的时候,无论 ...
- log4j 日志配置
Log4j教程 - Log4j安装 Log4j API包是根据Apache软件许可证分发的. 最新的log4j版本,包括全源代码,类文件和文档可以在http://logging.apache.org/ ...
- Hibernate Log4j日志记录
Hibernate Log4j日志记录 欢迎来到Hibernate Log4j Logging示例.Hibernate 4在旧的hibernate版本中使用JBoss日志而不是slf4j.今天我们将研 ...
- 智能一代云平台(三十三):log4j日志研究
[前言] 日志对于一个系统的来说是必不可少,它可以让人们知道,系统当前运行的状况:最近对日志进行了一些实践,以下是自己在这个过程中收获的一些东西. [一些有趣的实验] 一.mybat ...
- log4j日志信息配置文件详解
转自 log4J 日志信息log4j.properties配置说明 使用log4j 记录日志甚是方便,其提供了两种日志配置方式,log4j.propertes和log4j.xml,这篇文件先贴出log ...
- Hibernate4.3.1搭建Log4J日志环境
导语:原项目中使用了log4j-1.2.8.jar,在 引入hibernate包后,提示报错,在构建路径中将log4j-1.2.8.jar删除后正常.但记录日志还需要用到log4j,以下方法可解决上述 ...
- Log4j日志框架介绍
日志是应用软件中不可缺少的部分,Apache的开源项目log4j是一个功能强大的日志组件,提供方便的日志记录.在apache网站:jakarta.apache.org/log4j 可以免费下载到Log ...
最新文章
- github的webhooks无法刷新config服务端的bus-refresh接口
- memcached+magent实现memcached集群
- hadoop上lzop的安装
- string相关库函数
- Javascript 创建书签小工具 (bilibili视频下载为例)
- “UNIX的名字是我起的”——对话UNIX开发者Brian W. Kernighan
- 电子元件 —— 继电器
- 用 js 写的 WebSocketHeartBeat,心跳检测
- 微信支付——微信H5支付实战教程(微信支付v3版本java)
- FLTK--轻量级C++跨平台GUI库
- app支付宝验证登录
- Win11怎么添加日语输入法
- c1语言学生综合测评,学生综合素质评语
- delphi 整理的常用函数
- win7系统解决耳机插口的问题
- 光刻胶分为:半导体光刻胶/LCD光刻胶/PBC光刻胶
- Java项目:springboot课程自动排课系统
- 计算机组成原理知识点总结(第3篇 第6章 计算机的运算方法)
- 编译Sophus报错: error: implicitly-declared 的参考解决方法
- android app崩溃后自动重启