为什么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&uuml;lc&uuml;* @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)相关推荐

  1. log4j日志输出性能优化-缓存、异步

    1.log4j已成为大型系统必不可少的一部分,log4j可以很方便的帮助我们在程序的任何位置输出所要打印的信息,便于我们对系统在调试阶段和正式运行阶段对问题分析和定位.由于日志级别的不同,对系统的性能 ...

  2. java自定义日志级别_自定义log4j日志级别

    因为项目中需要输出一些特别的日志来做数据统计.如果开启log4j提供的INFO日志级别,每天生成的日志文件就会变得越来越大.这样就得写个定 时任务来删除这个文件.为了只输出所需的日志级别,唯有自己定义 ...

  3. linux日志文件存放目录,Log4j 日志文件Linux/Mac/Windows通用存放位置设置方法

    log4j1/log4j2中category的配置以及log的输出位置(windows和linux通用的log输出位置) 一.场景和需求 假设我现在有3个独立的用project(暂时用maven关联起 ...

  4. Mybatis 的Log4j日志输出问题 - 以及有关日志的所有问题

    转载自   Mybatis 的Log4j日志输出问题 - 以及有关日志的所有问题 使用Mybatis的时候,有些时候能输出(主要是指sql,参数,结果)日志.有些时候就不能. 无法输出日志的时候,无论 ...

  5. log4j 日志配置

    Log4j教程 - Log4j安装 Log4j API包是根据Apache软件许可证分发的. 最新的log4j版本,包括全源代码,类文件和文档可以在http://logging.apache.org/ ...

  6. Hibernate Log4j日志记录

    Hibernate Log4j日志记录 欢迎来到Hibernate Log4j Logging示例.Hibernate 4在旧的hibernate版本中使用JBoss日志而不是slf4j.今天我们将研 ...

  7. 智能一代云平台(三十三):log4j日志研究

    [前言] 日志对于一个系统的来说是必不可少,它可以让人们知道,系统当前运行的状况:最近对日志进行了一些实践,以下是自己在这个过程中收获的一些东西. [一些有趣的实验]          一.mybat ...

  8. log4j日志信息配置文件详解

    转自 log4J 日志信息log4j.properties配置说明 使用log4j 记录日志甚是方便,其提供了两种日志配置方式,log4j.propertes和log4j.xml,这篇文件先贴出log ...

  9. Hibernate4.3.1搭建Log4J日志环境

    导语:原项目中使用了log4j-1.2.8.jar,在 引入hibernate包后,提示报错,在构建路径中将log4j-1.2.8.jar删除后正常.但记录日志还需要用到log4j,以下方法可解决上述 ...

  10. Log4j日志框架介绍

    日志是应用软件中不可缺少的部分,Apache的开源项目log4j是一个功能强大的日志组件,提供方便的日志记录.在apache网站:jakarta.apache.org/log4j 可以免费下载到Log ...

最新文章

  1. github的webhooks无法刷新config服务端的bus-refresh接口
  2. memcached+magent实现memcached集群
  3. hadoop上lzop的安装
  4. string相关库函数
  5. Javascript 创建书签小工具 (bilibili视频下载为例)
  6. “UNIX的名字是我起的”——对话UNIX开发者Brian W. Kernighan
  7. 电子元件 —— 继电器
  8. 用 js 写的 WebSocketHeartBeat,心跳检测
  9. 微信支付——微信H5支付实战教程(微信支付v3版本java)
  10. FLTK--轻量级C++跨平台GUI库
  11. app支付宝验证登录
  12. Win11怎么添加日语输入法
  13. c1语言学生综合测评,学生综合素质评语
  14. delphi 整理的常用函数
  15. win7系统解决耳机插口的问题
  16. 光刻胶分为:半导体光刻胶/LCD光刻胶/PBC光刻胶
  17. Java项目:springboot课程自动排课系统
  18. 计算机组成原理知识点总结(第3篇 第6章 计算机的运算方法)
  19. 编译Sophus报错: error: implicitly-declared 的参考解决方法
  20. android app崩溃后自动重启

热门文章

  1. numpy教程:排序、搜索和计数
  2. android Toast五种特效
  3. python3源码安装_源码安装Python3
  4. 1020 月饼 (25 分)—PAT (Basic Level) Practice (中文)
  5. 洛达项目AB152xP资料SDK相关说明
  6. vmware虚拟机挂载Windows磁盘的两种方法
  7. Redis常用命令汇总
  8. 一个声明被new多次
  9. cmd窗口连接mongodb服务端
  10. 求10000以内n的阶乘(openjudge 2923)