5

マルチスレッド プログラムにいくつかの変更を加えてConcurrentModificationException、オブジェクトの で sを取得し始めたHashTableので、これへのすべてのアクセスをHashTableメソッドsynchronisedにして、オブジェクトへの同時アクセスを回避しましたが、予想とは異なり、問題は解決しませんでした。使用したデザインの概要は次のとおりです。

最初にJTable、usb デバイスのデータを表示する があります。これは、必要なデータをオブジェクトを介しJTableて実装する通信コア オブジェクトObserver(デバイスにデータを読み書きするObservableオブジェクト) を要求します。必要なデータは依存します。どの行が表示されるので、ユーザーがテーブルをスクロールすると更新されます。この通信コア オブジェクトは、使用後に最後に読み取った値を保存する他のメソッドsynchronized updateを呼び出すメソッドを介してこの通知を取得します (この通信クラスは、私のクラスに通知します)。および他のオブジェクトを介して値を読み取る場合)。の更新中に、この最後のメソッドで例外が発生しています。コードを簡略化すると、次のようになります。synchronizedHashTableJTableObservableHashTable

以下のメソッドは、通信コア オブジェクトのメソッドです。

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

HashTableUSBデバイスから値を要求する複数のウィンドウがあり、この通信オブジェクトがそれを処理するため、このアプローチが必要です。これを最後の値に追加する前は、同時実行性に問題はありませんでした。これ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));
    }
4

1 に答える 1

12
for (Parameter key : m_lastValues.keySet()) // exception this line
{
    // removes the currently not used parameters from the HashTable
}

問題はここにあります。同期に関係なく、反復処理中にコレクションを変更することはできません。実際にはシングルスレッドの問題です。

できることは、明示的なイテレータに切り替えて、アイテムを使用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;
        }
    }
}
于 2012-11-01T11:22:13.197 に答える