[英]How can I iterate over (system) properties in a thread safe manner?
The following piece starts throwing ConcurrentModificationException
in my application (in the iterator):以下部分开始在我的应用程序中(在迭代器中)抛出
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)
}
I am running a multi-threaded application, and unfortunately I do not have access to the code that is modifying the system properties (it could even be a third party library).我正在运行一个多线程应用程序,不幸的是我无法访问修改系统属性的代码(它甚至可能是第三方库)。
To fix that, we can take a snapshot of system property keys:为了解决这个问题,我们可以拍摄系统属性键的快照:
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!
}
Notice the value
comment - while stringPropertyNames
states set of keys in this property list where the key and its corresponding value are strings
, the system property could have been changed in the meantime.请注意
value
注释 - 虽然stringPropertyNames
声明set of keys in this property list where the key and its corresponding value are strings
,但同时系统属性可能已更改。
Why so much legwork?怎么跑这么多腿?
System properties are an instance of java.util.Properties
, and its methods getProperty
, setProperty
are thread-safe.系统属性是
java.util.Properties
一个实例,其方法getProperty
、 setProperty
是线程安全的。
Unfortunately, Properties' entry set's iterator (which I had used in question) is not thread-safe:不幸的是,属性的条目集的迭代器(我曾经使用过)不是线程安全的:
If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined
如果在对集合进行迭代时修改了映射(除了通过迭代器自己的删除操作,或者通过迭代器返回的映射条目上的 setValue 操作),迭代的结果是未定义的
So actually when I was iterating over that map, some system property was modified (= that entry said was modified), which caused CME to be thrown.所以实际上当我迭代那个地图时,一些系统属性被修改(=那个条目被修改),这导致 CME 被抛出。
This q&a pair also applies to any generic Properties
usage - just system properties make it trickier, with ability to access them directly with statics such as java.lang.System.setProperty(String, String)
- so controlling all accesses (especially in shared code) gets harder.这个问答对也适用于任何通用的
Properties
使用 - 只是系统属性使它变得更棘手,能够使用静态变量直接访问它们,例如java.lang.System.setProperty(String, String)
- 因此控制所有访问(尤其是在共享代码中) ) 变得更难。
You could wrap your properties in a ConcurrentHashMap
so that any of your compound actions such as iteration, navigation, check-and-act, etc.. will be thread-safe.您可以将您的属性包装在
ConcurrentHashMap
以便您的任何复合操作(例如迭代、导航、检查和操作等)都是线程安全的。 eg例如
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());
}
Note that the iterators returned by the ConcurrentHashMap
are weekly consistent , which means it may or may not reflect the changes to the collection after the construction of the iterator.请注意,
ConcurrentHashMap
返回的迭代器是每周一致的,这意味着它可能会也可能不会反映迭代器构建后对集合的更改。 If this is not what you wanted, you could use the Collections.synchronizedMap()
instead, which pays some penalties in concurrency.如果这不是你想要的,你可以使用
Collections.synchronizedMap()
代替,它会在并发方面付出一些代价。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.