2

我有收集所有与此代码是一个码头web服务器内运行一个给定的前缀Java属性variabile的:设置属性,而迭代键

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; 
} 

启动系统的属性键码,同时请求被执行这段代码,它可能发生的另一个请求写Java系统属性里面像一个简单的System.setProperty("test", "foo");

有了这个场景我得到一个ConcurrentModificationException而我迭代的属性和另一个请求更改的新重点它。

java.util.ConcurrentModificationException 
    at java.util.Hashtable$Enumerator.next(Hashtable.java:1378) 

其设置新的属性是完全相对于一个迭代的钥匙另一个流,但因为SystemProperties是在所有的JVM实例共享,我得到这个错误代码。

我已经发现了其他处理这个主题的主题,最推荐的解决方案是使用ConcurrentHashMap。这个选项对我来说不可用,因为我不是创建SystemProperties映射的映射,但我只是读/写它。

为了再现你可以简单地迭代循环

在这里是一个推荐的做法,以解决问题的结束括号前添加一个setProperty调用的问题?

+0

您可能希望只有一个线程能够在任何给定时间修改系统属性。 – Mena

+0

你如何更新属性?使用'System.setProperty'? – manouti

回答

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

关于第二点,这里的问题是迭代后不应用修改,它们是2个不同的e分离流。 –

+0

因此,您需要在开始循环之前克隆列表或将原始Set封装在java.util.concurrent类型的包中(如CopyOnWriteArraySet http://docs.oracle.com/javase/7/docs/api/java/util /concurrent/CopyOnWriteArraySet.html) – fandango

+0

问题是,当你去克隆集合,那么你可以有与OP相同的问题,因为它遍历属性'HashTable'。 – Gray

0

我认为,你应该创建一个锁定对象,并使用​​块,只要你尝试读/写性能对象。

public final Object systemPropLockObject = new Object(); 

synchronized (systemPropLockObject) { 
    // write the code to read/write to the system properties 
} 
0

有了这个场景我得到一个ConcurrentModificationException的,而我迭代的属性和另一个请求改变它。

我认为这个错误试图告诉你,你正在使用System属性不当。尽管它们支持HashTable,但它们并不是被设计为同时迭代和更新的。

在看HashTable代码,我看到了很多这样的评论:

如果地图同时修改了设置的迭代过程中(除了通过迭代器自己的remove操作,或者通过迭代器返回的映射条目上的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实施不同的解决方案似乎对我更好。