由[Ljava.lang.StackTraceElement;@14e77f0发现的一个问题

产品在测试环境部署了好几天,才发现有一个ERROR:2013-01-23 14:22:33,122 ERROR [com.XXX.XXX.XXX.db.timer.BaseTimer.run] - [Ljava.lang.StackTraceElement;@14e77f0。

在茫茫的日志文件中,这样一条ERROR实在不是一眼就发现的。要反思下,看来以后要定期在日志中进行搜索,看看有没有ERROR了。

令我疑惑的是,明明所有的异常,我都是在日志中记录其堆栈跟踪的啊,这里怎么就只有一行光秃秃的ERROR呢?

下面是打印出上面那条ERROR的代码:

catch(Exception ex) {
    logger.error(ex.getStackTrace());
}

参考http://stackoverflow.com/questions/2245088/how-to-display-stack-trace-on-a-caught-exception后发现,error(Throwable ex)只会打印出ex的对象信息,并不会打印完整的堆栈跟踪。

正确的方法是,调用error(Object, Throwable)方法。如下:

catch(Exception ex) {
    logger.error(ex, ex);
}

 

好,到此可以打印出完整的错误日志了。发现了这样一条异常:java.util.ConcurrentModificationException。

抛异常的代码如下:

List list = ....
for(Iterator it=list.iterator(); it.hasNext()) {
    Object o = it.next();
    if(...) {
        list.remove(o);
    }   
}

一番研究发现,Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭 代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

 

posted on 2013-01-31 15:33  张孝军  阅读(21822)  评论(0)    收藏  举报

导航