这里是JDK Properties.list
的实现:
public void list(PrintWriter out) {
out.println("-- listing properties --");
Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
String key = e.nextElement();
String val = (String)h.get(key);
if (val.length() > 40) {
val = val.substring(0, 37) + "...";
}
out.println(key + "=" + val);
}
}
行是什么
Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
有关?它不能只使用原始表而不是复制并从中读取数据吗?
答案 0 :(得分:2)
这是允许线程安全迭代的常用习惯用法(即,如果另一个线程在循环期间修改哈希表,则可能出现ConcurrentModificationException
。)
答案 1 :(得分:2)
list()
方法未同步。
因此,在Properties
调用期间list()
实例上的任何调用(甚至那些已同步)都可能会破坏对象的状态并导致异常或逻辑损坏。
假设使用中间的Properties实例,我们直接在Properties
实例上迭代,它将不是线程安全的
假设我们有两个线程:调用此list()
方法的线程A和在同一remove()
实例上调用Properties
的线程B.
list()
方法中的此代码具有多种竞争条件。
为了说明,我们可以使用list()方法的这个片段:
String key = e.nextElement();
String val = (String)h.get(key);
if (val.length() > 40) {
假设在此指令后线程A暂停:
String key = e.nextElement();
线程B恢复并使用作为参数调用与线程A检索到的密钥相关联的对象instance.remove()
然后当线程A恢复时,它转到下一条指令:
String val = (String)h.get(key);
该值不再存在。
下一条指令引发异常,因为val为null
:
if (val.length() > 40) {
答案 2 :(得分:1)
这是多线程应用程序的优化。
Properties
对象意味着线程安全,因此他们必须使方法同步(这是一个坏主意,因为写入PrintStream
可能会阻塞很长时间,持有锁定),或者他们可以快速将内容复制到同步块中的新哈希表(enumerate
已同步),然后打印副本的项目,而不需要锁定。