0

下面的代码由线程池执行。首先,地图不是并发的,所以我已经改变了它,但我仍然在第二行得到修改异常。为了使这段代码成为线程安全的,我应该进行哪些更改?

ConcurrentHashMap<String, Account> entriesOnFile = IniReaderHelper.load();
for (Map.Entry<String,Account> entryFromFile: entriesOnFile.entrySet())
{
    EntryWrapper wrapperFromEntriesFile = new EntryWrapper(entryFromFile.getValue());
    if (wrapperFromEntriesFile.getName().equals(entryName))
    {
        Tracer.info("Found matching entry from the entries file for +'" + entryName + "'");
        synchronized(this) 
        {
            context.put(RequestServices.ENTRY_WRAPPER, wrapperFromEntriesFile);
        }
        entry = wrapperFromEntriesFile;
        break;
    }               
}

更多信息:下面是返回地图的 .load() 函数的代码:

static public ConcurrentHashMap<String, Account> load() throws Exception
{
    BufferedReader reader = null;
    accounts.clear();
    try
    {
        reader = new BufferedReader(new FileReader(getEntriesFile()));
        Account current = null;
        String accountName;
        String line;
        while ((line = reader.readLine()) != null)
        {
                ... do stuff here then adding entry to the amp
                accounts.put(accountName, current);
        }
    }
    finally
    {
        if (reader != null)
            reader.close();
    }
    return accounts;
}

这是堆栈跟踪:

error code [1] : java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$EntryIterator.next(Unknown Source)
at java.util.HashMap$EntryIterator.next(Unknown Source)
at .....call(AsyncCommand.java:78)

堆栈跟踪指向第二行('for'循环),它写“EntryIterator.next”,所以这不意味着我应该改变:

for (Map.Entry<String,Account> entryFromFile: entriesOnFile.entrySet())

for (ConcurrentHashMap.Entry<String,Account> entryFromFile: entriesOnFile.entrySet())

这是“帐户”的声明

private static ConcurrentHashMap<String, Account> accounts = new ConcurrentHashMap<String, Account>();
4

2 回答 2

0

据我所见,跨线程共享帐户映射毫无意义(您在每次调用 load() 时都在清除和重建映射,因此最直接的解决方法是删除共享静态映射(帐户)并加载() 在每次调用时创建并返回一个新的 Map。

于 2013-06-13T06:06:59.407 回答
0

在我看来,从你迄今为止所说的来看,地图是完全共享的。在让另一个线程改变帐户字段之前,您可以同步对 load 方法的访问并复制地图的内容。另一种选择是更改加载方法以接受它可以填充的地图,而不是让它改变一个共享的地图。

话虽如此,例外没有意义。CHM 不返回 HashMap$EntryIterator,它返回 ConcurrentHashMap$EntryIterator 并且没有办法抛出您在此处描述的堆栈。我的猜测是您没有运行您发布的代码,而是错误地运行旧版本。尝试在调试器中运行,或添加日志语句以验证发布的代码是否实际运行。

于 2013-06-13T07:53:46.620 回答