public class AsyncAppender extends AppenderSkeleton implements AppenderAttachable {
public static final int DEFAULT_BUFFER_SIZE = 128 ;
private final List buffer = new ArrayList();
private final Map discardMap = new HashMap();
private int bufferSize = 128 ;
AppenderAttachableImpl aai;
private final AppenderAttachableImpl appenders = new AppenderAttachableImpl();
private final Thread dispatcher;
private boolean locationInfo = false ;
private boolean blocking = true ;
public AsyncAppender () {
this .aai = this .appenders;
this .dispatcher = new Thread(new AsyncAppender.Dispatcher(this , this .buffer, this .discardMap, this .appenders));
this .dispatcher.setDaemon(true );
this .dispatcher.setName("AsyncAppender-Dispatcher-" + this .dispatcher.getName());
this .dispatcher.start();
}
public void addAppender (Appender newAppender) {
AppenderAttachableImpl var2 = this .appenders;
synchronized (this .appenders) {
this .appenders.addAppender(newAppender);
}
}
public void append (LoggingEvent event) {
if (this .dispatcher != null && this .dispatcher.isAlive() && this .bufferSize > 0 ) {
event.getNDC();
event.getThreadName();
event.getMDCCopy();
if (this .locationInfo) {
event.getLocationInformation();
}
event.getRenderedMessage();
event.getThrowableStrRep();
List var11 = this .buffer;
synchronized (this .buffer) {
while (true ) {
int previousSize = this .buffer.size();
if (previousSize < this .bufferSize) {
this .buffer.add(event);
if (previousSize == 0 ) {
this .buffer.notifyAll();
}
break ;
}
boolean discard = true ;
if (this .blocking && !Thread.interrupted() && Thread.currentThread() != this .dispatcher) {
try {
this .buffer.wait();
discard = false ;
} catch (InterruptedException var8) {
Thread.currentThread().interrupt();
}
}
if (discard) {
String loggerName = event.getLoggerName();
AsyncAppender.DiscardSummary summary = (AsyncAppender.DiscardSummary)this .discardMap.get(loggerName);
if (summary == null ) {
summary = new AsyncAppender.DiscardSummary(event);
this .discardMap.put(loggerName, summary);
} else {
summary.add(event);
}
break ;
}
}
}
} else {
AppenderAttachableImpl var2 = this .appenders;
synchronized (this .appenders) {
this .appenders.appendLoopOnAppenders(event);
}
}
}
...
private static class Dispatcher implements Runnable {
private final AsyncAppender parent;
private final List buffer;
private final Map discardMap;
private final AppenderAttachableImpl appenders;
public Dispatcher (AsyncAppender parent, List buffer, Map discardMap, AppenderAttachableImpl appenders) {
this .parent = parent;
this .buffer = buffer;
this .appenders = appenders;
this .discardMap = discardMap;
}
public void run () {
boolean isActive = true ;
try {
while (isActive) {
LoggingEvent[] ex = null ;
List i = this .buffer;
synchronized (this .buffer) {
int bufferSize = this .buffer.size();
for (isActive = !this .parent.closed; bufferSize == 0 && isActive; isActive = !this .parent.closed) {
this .buffer.wait();
bufferSize = this .buffer.size();
}
if (bufferSize > 0 ) {
ex = new LoggingEvent[bufferSize + this .discardMap.size()];
this .buffer.toArray(ex);
int index = bufferSize;
for (Iterator iter = this .discardMap.values().iterator(); iter.hasNext(); ex[index++] = ((AsyncAppender.DiscardSummary)iter.next()).createEvent()) {
;
}
this .buffer.clear();
this .discardMap.clear();
this .buffer.notifyAll();
}
}
if (ex != null ) {
for (int var12 = 0 ; var12 < ex.length; ++var12) {
AppenderAttachableImpl var13 = this .appenders;
synchronized (this .appenders) {
this .appenders.appendLoopOnAppenders(ex[var12]);
}
}
}
}
} catch (InterruptedException var11) {
Thread.currentThread().interrupt();
}
}
}
private static final class DiscardSummary {
private LoggingEvent maxEvent;
private int count;
public DiscardSummary (LoggingEvent event) {
this .maxEvent = event;
this .count = 1 ;
}
public void add (LoggingEvent event) {
if (event.getLevel().toInt() > this .maxEvent.getLevel().toInt()) {
this .maxEvent = event;
}
++this .count;
}
public LoggingEvent createEvent () {
String msg = MessageFormat.format("Discarded {0} messages due to full event buffer including: {1}" , new Object[]{new Integer(this .count), this .maxEvent.getMessage()});
return new LoggingEvent("org.apache.log4j.AsyncAppender.DONT_REPORT_LOCATION" , Logger.getLogger(this .maxEvent.getLoggerName()), this .maxEvent.getLevel(), msg, (Throwable)null );
}
}
}
总结:
一个缓冲区buffer,为了减少读写硬盘次数,提高cpu效率,避免过多的中断切换。 一个Map对生产者速度远大于消费者地补救措施 一个后台线程不断进行写入磁盘地操作