同步方法中的并发修改异常

Her*_*nis 4 java multithreading synchronization

我做了一些修改,我的多线程程序,并开始获得ConcurrentModificationException一个物体的S- HashTable,所以我做的所有访问在此HashTablesynchronised方法,以避免并发访问我的对象,不像我期望它并没有解决问题.以下是使用的设计概述:

首先,我有一个JTable显示usb设备的一些数据,这JTable要求一个通信核心对象实现Observer(通过Observable对象读取和写入数据到我的设备)它想要的数据,它想要的数据取决于显示哪些行,以便在用户滚动de table时更新,此通信核心对象通过synchronized update调用其他synchronized更新方法的方法获取此通知,该方法HashTable保存最后读取的值(使用后此通信类通知我的JTable类)和其他对象,当它通过其他Observable对象读取值时).更新时,最后一种方法出现异常HashTable.这是代码的简化:

以下方法是通信核心对象

public synchronized void update(Observable o, Object arg)
{
    // do some other work
    // calls the second synchronized method
    updateMonitorList();
}

private synchronized void updateMonitorList()
{
    // updates a list of monitoring addresses (no problem here)
    // m_lastValues is the HashTable that is giving me headaches
    Iterator<Parameter> itr = m_lastValues.keySet().iterator();
    while (itr.hasNext())
    {
        // removes the currently not used parameters from the HashTable
        Parameter p = itr.next(); // concurrent exception here WHY? :/
        boolean contains = false;
        for (int i = 0; i < m_monitorList.size(); i++)
        {
            if (p.equals(m_monitorList.get(i)))
            {
                contains = true;
                break;
            }
        }
        if (!contains)
        {
            m_lastValues.remove(p);
        }
    }
    // more operations with the HashTable
    for (int i = 0; i < m_monitorList.size(); i++)
    {
        // adds newly added parameters to the hashtable
        boolean contains = false;
        for (Observer key : m_requestedParameters.keySet())
        {
            if (key.equals(m_monitorList.get(i)))
            {
                contains = true;
                break;
            }
        }
        if (!contains)
        {
            m_lastValues.put(m_monitorList.getAt(i), m_monitorList.getAt(i).m_intUserSetting);
        }
    }
}

// this method is used to know if a value has changed
private synchronized boolean getParameterChanged(Parameter currentParamer)
{
    Integer v = m_lastValues.get(currentParamer);
    return v == null || v != currentParamer.m_intUserSetting;
}
Run Code Online (Sandbox Code Playgroud)

我需要这种方法,因为我有多个窗口要求来自usb设备的值,并且这个通信对象负责它,在添加HashTable最后一个值之前并发没有问题.这m_lastValues HashTable不用于上面未列出的任何其他方法.

有什么建议?提前致谢.

[编辑]

实际上这不是一个多线程问题,它只是一个被误解的异常含义.正如@Tudor所指出的那样,问题就是循环remove()内部的方法while.这是我解决它的方式:

这段代码进入updateMonitorList()方法,请注意no Iterator was needed(第一个问题是这样的for循环),实际上Iterator没有区别:

    ArrayList<Parameter> remove = new ArrayList<Parameter>();
    for (Parameter p : m_lastValues.keySet())
    {
        boolean contains = false;
        for (int i = 0; i < m_monitorList.size(); i++)
        {
            if (p.equals(m_monitorList.get(i)))
            {
                contains = true;
                break;
            }
        }
        if (!contains)
        {
            remove.add(p);
        }
    }
    for (int i = 0; i < remove.size(); i++)
    {
        m_lastValues.remove(remove.get(i));
    }
Run Code Online (Sandbox Code Playgroud)

Tud*_*dor 12

for (Parameter key : m_lastValues.keySet()) // exception this line
{
    // removes the currently not used parameters from the HashTable
}
Run Code Online (Sandbox Code Playgroud)

问题出在这里.无论同步如何,您都无法在迭代时更改集合.实际上这是一个单线程问题.

您可以做的是切换到显式迭代器并使用remove()或保存要在单独的集合中删除的项目,然后将其删除.

Iterator<Parameter> iter = m_lastValues.keySet().iterator();
while (iter.hasNext()) {
    Parameter current = iter.next();
    for (int i = 0; i < m_monitorList.size(); i++) {
        if(current.equals(m_monitorList.get(i)) {
            iter.remove();
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)