[英]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.