繁体   English   中英

如何以线程安全的方式迭代(系统)属性?

[英]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一个实例,其方法getPropertysetProperty是线程安全的。

不幸的是,属性的​​条目集的迭代器(我曾经使用过)不是线程安全的:

如果在对集合进行迭代时修改了映射(除了通过迭代器自己的删除操作,或者通过迭代器返回的映射条目上的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM