我有一个代码,它收集以给定前缀
开头的所有系统属性键private static List<String> getKeysByPrefix(String prefix) {
Set<?> keySet = System.getProperties().keySet();
Iterator<?> iterator = keySet.iterator();
List<String> list = new ArrayList<>();
while (iterator.hasNext()) {
String key = (String) iterator.next();
if (key.startsWith(prefix)) {
list.add(key);
}
}
return list;
}
此代码在Jetty Web服务器内运行,当请求执行此代码时,可能会发生另一个请求在java System属性中写入一个新密钥,如简单System.setProperty("test", "foo");
在这个场景中,我正在迭代属性时获得ConcurrentModificationException
,而另一个请求会更改它。
java.util.ConcurrentModificationException
at java.util.Hashtable$Enumerator.next(Hashtable.java:1378)
设置新属性的代码完全是另一个流程,而不是迭代密钥,但因为SystemProperties在所有JVM实例之间共享,所以我收到了这个错误。
我已经找到了其他主题来处理这个主题,最常见的解决方案是使用ConcurrentHashMap。这个选项对我来说不可用,因为我不是那个创建SystemProperties地图的人,但我只是在读/写它。
为了重现该问题,您只需在迭代器循环的右括号之前添加setProperty
调用
这是建议的做法,以解决问题?
答案 0 :(得分:0)
迭代时无法更改列表。
两个选项:
使用CopyOnWriteArraySet尝试此操作:
Set<?> keySet = new CopyOnWriteArraySet<Object>(System.getProperties().keySet());
Iterator<?> iterator = keySet.iterator();
List<String> list = new ArrayList<String>();
while (iterator.hasNext()) {
String key = (String) iterator.next();
if (key.startsWith(prefix)) {
list.add(key);
}
}
return list;
答案 1 :(得分:0)
我相信你应该在尝试读取/写入属性对象时创建一个锁对象并使用synchronized
块。
public final Object systemPropLockObject = new Object();
synchronized ( systemPropLockObject ) {
// write the code to read/write to the system properties
}
答案 2 :(得分:0)
在这种情况下,我在获取ConcurrentModificationException时正在迭代属性而另一个请求会更改它。
我认为此错误试图告诉您,您正在不恰当地使用System
属性。即使它们由HashTable
支持,它们也不会被设计为同时迭代和更新。
在查看HashTable
代码时,我看到了很多评论:
如果在对集合进行迭代时修改了映射(除非通过迭代器自己的删除操作,或者通过迭代器返回的映射条目上的setValue操作),迭代的结果是未定义。
毋庸置疑,这并不好。
我已经找到了其他主题来处理这个主题,最常见的解决方案是使用ConcurrentHashMap。这个选项对我来说不可用,因为我不是那个创建SystemProperties地图的人,而是我只读/写它。
您是否有一个共享类,它使用初始系统属性映射的内容初始化CHM,但然后读取/写入CHM?
如果您在不谈论属性的情况下编辑问题并谈论自己的需求,那么我们可以提出更好的答案。
最后,如果你绝望了,你的迭代周围的锁可以工作:
Properties props = System.getProperties();
List<String> list = new ArrayList<>();
synchronized (props) {
// get the properties which match with an enumeration inside the lock
...
}
这取决于系统属性如何锁定自身,但这可能对您有用。使用CHM实现不同的解决方案对我来说似乎更好。