您在发布的代码中看到的for-each迭代器不会抛出此异常!!!
我在我的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)
您在发布的代码中看到的for-each迭代器不会抛出此异常!!!
Application.onCreate()
没有并发访问权。
这里是您参考的源代码:https://android.googlesource.com/platform/libcore/+/android-6.0.1_r54/luni/src/main/java/java/util/logging/。
我强烈建议您阅读源代码,这必须有助于理解我解释的内容。
让我们在第一个代码块中到达Handler[] handlers = rootLogger.getHandlers();
。 Logger.getHandlers()
的实施是:
public Handler[] getHandlers() {
return handlers.toArray(EMPTY_HANDLERS_ARRAY);
}
和Logger.removeHandler(Handler)
的核心部分是,在Logger.java中:
private final List<Handler> handlers = new CopyOnWriteArrayList<Handler>();
public void removeHandler(Handler handler) {
......
this.handlers.remove(handler);
updateDalvikLogHandler();
}
所以我们可以看到第一个代码块中发布的logger.removeHandler(handler);
没有抛出异常。
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();
}
......
}
异常的确切原因是在调用Logger.children
时某处修改了for (Logger logger : children)
。
Logger.java的评论说它的所有方法都是线程安全的。
我完全混淆Logger.children
中发生的事件LogManager
。但是我的代码没有调用meteor npm install
。
我相信我需要有人帮助我澄清我的想法,并帮助找到错误。
非常感谢阅读长篇文章...答案 0 :(得分:0)
我无法发表评论,所以我会将其作为答案发布。
如果您对for-each代码发表评论,是否会引发异常?
我怀疑抛出异常是因为您在代码中的其他位置执行logger
后修改logger = rootLogger
并且系统也在修改它。
答案 1 :(得分:0)
在java.util.logging.Logger.java中:
/**
* Child loggers. Should be accessed only while synchronized on {@code
* LogManager.getLogManager()}.
*/
final List<Logger> children = new ArrayList<Logger>();
显然Logger.updateDalvikLogHandler()
中的子级循环被调用而无需同步。
for (Logger logger : children) {
logger.updateDalvikLogHandler();
}
您可能正在其他类中创建记录器,例如
static final LOG = Logger.getLogger(MyClass.class.getName())
依次更新Logger.children属性。
可以从主线程以外的其他位置调用。当您从其他线程使用MyClass时,静态字段初始化将创建新的记录器,该记录器将更新根记录器的子代属性。
在这种情况下,我认为在不同步到LogManager的情况下使用children属性是Logger中的错误。
解决方法是在同步块中调用日志记录初始化
synchronized (LogManager.getLogManager()) {
Handler[] handlers = rootLogger.getHandlers();
for (Handler handler : handlers) {
rootLogger.removeHandler(handler);
}
rootLogger.addHandler(rootHandler);
rootLogger.setLevel(fileLogLevel);
}