另一种常用的方案可以使用生产者和消费中的模式来实现类似的逻辑。即每一次请求做为一个生产者,将请求放到一个Queue中,而由另外一个或多个消费者读取Queue中的内容以处理真正的逻辑。
在最新的Java版本中,我们可以使用BlockingQueue类简单的实现类似的需求,然而由于Log4J的存在远早于BlockingQueue的创建,因而为了实现对以前版本的兼容,它还是自己实现了这样一套生产者消费者模型。
AsyncAppender并不会在每一次的doAppend()调用中都直接将消息输出,而是使用了buffer,即只有等到buffer中LoggingEvent实例到达bufferSize个的时候才真正的处理这些消息,当然我们也可以讲bufferSize设置成1,从而实现每一个LoggingEvent实例的请求都会直接执行。如果bufferSize设置过大,在应用程序异常终止时可能会丢失部分日志。
1 public static final int DEFAULT_BUFFER_SIZE = 128;
2 private final List buffer = new ArrayList();
3 private final Map discardMap = new HashMap();
4 private int bufferSize = DEFAULT_BUFFER_SIZE;
5 private final Thread dispatcher;
6 private boolean locationInfo = false;
7 private boolean blocking = true;
对其他字段,discardMap用于存放当当前LoggingEvent请求数已经超过bufferSize或当前线程被中断的情况下能继续保留这些日志信息;locationInfo用于设置是否需要保留位置信息;blocking用于设置在消费者正在处理时,是否需要生产者“暂停”下来,默认为true;而dispatcher即是消费者线程,它在构建AsyncAppender是启动,每次buffer这个list,如果发现buffer中存在LoggingEvent实例,则将所有buffer和discardMap中的LoggingEvent实例拷贝到数组中,清空buffer和discardMap,并调用AsyncAppender内部注册的Appender实例打印日志。
1 public void run() {
2boolean isActive = true;
3try {
4while (isActive) {
5LoggingEvent[] events = null;
6synchronized (buffer) {
7int bufferSize = buffer.size();
8isActive = !parent.closed;
9
10while ((bufferSize == 0) && isActive) {
11buffer.wait();
12bufferSize = buffer.size();
13isActive = !parent.closed;
14}
15if (bufferSize > 0) {
16events = new LoggingEvent[bufferSize
17+ discardMap.size()];
18buffer.toArray(events);
19int index = bufferSize;
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-29497-27.html
好帅
期待
中国可以在附近海