簡體   English   中英

迭代器的並發修改異常

[英]concurrent modification exception with iterator

我對Java相當陌生,實際上是在編寫鍵盤記錄程序,並使其定期寫入文件。 每當用戶按下一個鍵時,它都會實例化一個NativeKeyEvent,該NativeKeyEvent調用“ paramString()”並將信息作為字符串添加到下面的arraylist中。

public static ArrayList<String> stringArray = new ArrayList<String>();

public synchronized String paramString() {
    StringBuilder param = new StringBuilder(255);
    // other code
    stringArray.add(param.toString());
}

然后,在每個間隔處傳遞字符串數組,並將其寫入下面的TimerTask線程中的文件...

public class SaveToArrayAndWriteTask extends TimerTask {

private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;
private static String str;

   @Override
   public synchronized void run() {
     openFile();
     writeToFile(anotherArray);
     closeFile();
   }

   private static synchronized void writeToFile(ArrayList<String> localArray) {

    Iterator<String> iterator = localArray.iterator();
    try {
        while (iterator.hasNext()) {
            str = iterator.next().toString();
            output.format("%s\n", str);
        }
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

這行'str = iterator.next()。toString();' 如果在程序錄制/添加另一個按鍵時嘗試遍歷arraylist並將其寫入文件,則拋出異常。 我認為通過將stringArray(正在被修改)放入anotherArray並將其作為參數傳遞將阻止這種情況的發生。 如您所見,我已經嘗試過使用synced關鍵字,並且還嘗試將其放入另一個線程中,並閱讀了關於stackoverflow的其他各種文章,但無濟於事。

解決此問題的最佳方法是什么?

您不是在復制ArrayList,而是在另一個引用相同的ArrayList。

private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;

應該是這樣的:

private ArrayList<String> copy = new ArrayList<>(NativeKeyEvent.stringArray);

這將創建一個數組ArrayList,其元素與NativeKeyEvent.stringArray相同。

我建議使用getter而不是將stringArray公開為公共變量。 getter應該復制stringArray並返回它。 這樣, stringArray任何使用者都將在副本上進行操作,並且無法修改列表。

我想通過將stringArray(正在被修改)放入anotherArray

private ArrayList<String> anotherArray = NativeKeyEvent.stringArray;

沒有創建新的ArrayList。 anotherArray仍在引用同一對象。 您需要創建一個新的ArrayList,其中包含stringArray的元素。

private ArrayList<String> anotherArray = new ArrayList<>(NativeKeyEvent.stringArray);

一般而言,如果在迭代集合時對其進行修改,則會收到ConcurrentModificationException

您有兩種選擇:

困難的方法:同步對列表的訪問,以便其他線程在迭代時阻塞

簡單的方法:使用java.util.concurrent包中的CopyOnWriteArrayList列表實現,它為您完成了所有艱苦的工作

public static ArrayList<String> stringArray = new CopyOnWriteArrayList<String>();

而已。 不再需要,您可以刪除所有同步。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM