[英]How can I iterate over (system) properties in a thread safe manner?
以下部分开始在我的应用程序中(在迭代器中)抛出ConcurrentModificationException
:
final Map<?, ?> systemProperties = System.getProperties()
final Map<String, String> properties = (Map<String, String>) systemProperties
for (final Entry<String, String> entry : properties.entrySet()) { // exception here
System.out.println(entry)
}
我正在运行一个多线程应用程序,不幸的是我无法访问修改系统属性的代码(它甚至可能是第三方库)。
为了解决这个问题,我们可以拍摄系统属性键的快照:
final Properties systemProperties = System.getProperties()
final Set<String> keys = systemProperties.stringPropertyNames()
for (final String key : keys) {
System.out.println("key: " + key)
final String value = systemProperties.getProperty(key)
System.out.println("value: " + value) // value can be null!
}
请注意value
注释 - 虽然stringPropertyNames
声明set of keys in this property list where the key and its corresponding value are strings
,但同时系统属性可能已更改。
怎么跑这么多腿?
系统属性是java.util.Properties
一个实例,其方法getProperty
、 setProperty
是线程安全的。
不幸的是,属性的条目集的迭代器(我曾经使用过)不是线程安全的:
如果在对集合进行迭代时修改了映射(除了通过迭代器自己的删除操作,或者通过迭代器返回的映射条目上的 setValue 操作),迭代的结果是未定义的
所以实际上当我迭代那个地图时,一些系统属性被修改(=那个条目被修改),这导致 CME 被抛出。
这个问答对也适用于任何通用的Properties
使用 - 只是系统属性使它变得更棘手,能够使用静态变量直接访问它们,例如java.lang.System.setProperty(String, String)
- 因此控制所有访问(尤其是在共享代码中) ) 变得更难。
您可以将您的属性包装在ConcurrentHashMap
以便您的任何复合操作(例如迭代、导航、检查和操作等)都是线程安全的。 例如
ConcurrentHashMap<String, String> props = new ConcurrentHashMap<>(
(Map<String, String>)(Object)System.getProperties());
for(Map.Entry<String, String> entry: props.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
请注意, ConcurrentHashMap
返回的迭代器是每周一致的,这意味着它可能会也可能不会反映迭代器构建后对集合的更改。 如果这不是你想要的,你可以使用Collections.synchronizedMap()
代替,它会在并发方面付出一些代价。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.