非常奇怪:android:java.util.logging.Logger.removeHandler抛出ConcurrentModificationException 注意!!!

非常奇怪:android:java.util.logging.Logger.removeHandler抛出ConcurrentModificationException 注意!!!,java,android,Java,Android,对于您在发布的代码中看到的每个迭代器,不会引发此异常 我在android应用程序中遇到了一个非常奇怪的ConcurrentModificationException import java.util.logging.Handler; import java.util.logging.Logger; public MyApp extends Application { private static final Logger rootLogger = Logger.getLogger("")

对于您在发布的代码中看到的每个迭代器,不会引发此异常

我在android应用程序中遇到了一个非常奇怪的ConcurrentModificationException

import java.util.logging.Handler;
import java.util.logging.Logger;
public MyApp extends Application {
    private static final Logger rootLogger = Logger.getLogger("");
    @override
    public void onCreate() {
        super.onCreate();
        ......
        Handler[] handlers = rootLogger.getHandlers();
        for (Handler handler : handlers) {
            rootLogger.removeHandler(handler);
        }
        rootLogger.addHandler(rootHandler);
        rootLogger.setLevel(fileLogLevel);
    }
}
在非常偶然的情况下,当我通过单击桌面图标启动应用程序时,有一个例外:

Caused by: java.util.ConcurrentModificationException
E/AndroidRuntime(26111): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
E/AndroidRuntime(26111): at java.util.logging.Logger.updateDalvikLogHandler(Logger.java:232)
E/AndroidRuntime(26111): at java.util.logging.Logger.updateDalvikLogHandler(Logger.java:233)
E/AndroidRuntime(26111): at java.util.logging.Logger.removeHandler(Logger.java:486)
注意!!! 对于您在发布的代码中看到的每个迭代器,不会引发此异常

Application.onCreate()
没有并发访问权限

以下是供您参考的源代码:

我强烈建议您阅读源代码,这必须有助于理解我下面解释的内容

===这就是我为例外情况所做的研究=== 让我们转到这里
Handler[]handlers=rootLogger.getHandlers()
Logger.getHandlers()的实现是:

public Handler[] getHandlers() {
    return handlers.toArray(EMPTY_HANDLERS_ARRAY);
}
在Logger.java中,
Logger.removeHandler(Handler)
的核心部分是:

private final List<Handler> handlers = new CopyOnWriteArrayList<Handler>();
public void removeHandler(Handler handler) {
    ......
    this.handlers.remove(handler);
    updateDalvikLogHandler();
}
for (Logger logger : children) { // this line in crash trace
    logger.updateDalvikLogHandler();
}
这是异常跟踪的最后一个条目,在ArrayList.java中:

public E next() {
    ArrayList<E> ourList = ArrayList.this;
    int rem = remaining;
    if (ourList.modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    ......
}
public E next(){
ArrayList ourList=ArrayList.this;
int rem=剩余;
if(ourList.modCount!=expectedModCount){
抛出新的ConcurrentModificationException();
}
......
}
异常的确切原因是调用(Logger-Logger:children)
时,在某个地方修改了
Logger.children

java的评论说它的所有方法都是线程安全的

===我的解释结束,我的问题开始=== 我完全搞不懂在中修改的
Logger.children
。但是我的代码不调用
LogManager

我相信我需要有人帮助我澄清我的想法,并帮助找到错误


非常感谢您阅读这篇长篇博文……

我无法发表评论,因此我将发布这篇博文作为答案

如果您对每个代码的注释,是否会引发异常


我怀疑引发异常是因为您在代码的其他地方执行了
logger=rootLogger
之后正在修改
logger
,并且系统也在修改它。

我无法发表评论,因此我会将此作为答案发布

如果您对每个代码的注释,是否会引发异常

我怀疑引发异常是因为您在代码的其他地方执行了
logger=rootLogger
之后正在修改
logger
,并且系统也在修改它。

中:

您可能正在其他类中创建记录器,例如

static final LOG = Logger.getLogger(MyClass.class.getName())
从而更新Logger.children属性

这可以从主线程以外的其他线程调用。当您从其他线程使用MyClass时,静态字段初始化将创建新的记录器,该记录器将更新根记录器的子属性

在这种情况下,我认为使用日志属性不同步到LogMealgor。 解决方法是在同步块中调用日志初始化

synchronized (LogManager.getLogManager()) {
    Handler[] handlers = rootLogger.getHandlers();
    for (Handler handler : handlers) {
        rootLogger.removeHandler(handler);
    }
    rootLogger.addHandler(rootHandler);
    rootLogger.setLevel(fileLogLevel);
}
在:

您可能正在其他类中创建记录器,例如

static final LOG = Logger.getLogger(MyClass.class.getName())
从而更新Logger.children属性

这可以从主线程以外的其他线程调用。当您从其他线程使用MyClass时,静态字段初始化将创建新的记录器,该记录器将更新根记录器的子属性

在这种情况下,我认为使用日志属性不同步到LogMealgor。 解决方法是在同步块中调用日志初始化

synchronized (LogManager.getLogManager()) {
    Handler[] handlers = rootLogger.getHandlers();
    for (Handler handler : handlers) {
        rootLogger.removeHandler(handler);
    }
    rootLogger.addHandler(rootHandler);
    rootLogger.setLevel(fileLogLevel);
}

创建数组/列表的副本,如
newarraylist(handlers)
。您不应该在遍历集合时将其从集合中删除。@JaredBurrows如果我发布的foreach没有引发异常,请阅读
注释
。创建数组/列表的副本,如
新建数组列表(处理程序)
。您不应该在遍历集合时将其从集合中删除。@JaredBurrows如果我发布的foreach没有引发异常,请阅读
注释
rootLogger
仅在我发布的位置访问。。。我已经搜索了该项目。
rootLogger
仅在我发布的地方被访问。。。我已经搜索了这个项目。