当我尝试将消息写入文件时java.util.ConcurrentModificationException

时间:2015-05-17 10:08:40

标签: java

我是一名初级Java开发人员。我想用GUI编写电子邮件客户端,但是当我尝试运行WriteMessages线程时遇到问题。我正在使用JavaMail库。

public class WriteMessages implements Runnable {

    private List<Message> list;
    private Properties properties;
    private Utilities util = new Utilities();

    public WriteMessages(List<Message> list, Properties properties) {
        this.list = list;
        this.properties = properties;
    }

    @Override
    public void run() {

        Iterator<Message> iter = list.iterator();
        while (iter.hasNext()) {

            Message m = iter.next(); //line 42 exception occurs there

            String name = Morda.produceFileName(m);

            File file = new File(properties.getProperty("PathToMessages") + "//" + name);
            try {
                file.createNewFile();
            } catch (IOException ex) {
            }

            try (OutputStream os = new FileOutputStream(file);){
                m.writeTo(os);
                System.out.println("File " + file.getName() + " was wrote succesfuly");
            } catch (IOException | MessagingException ex) {
            }
        }
    }
}

我明白了:

Message 0 added successfully.
Message 1 added successfully.
Message 2 added successfully.
Message 3 added successfully.
Thread is interrupted.
File 2011_07_17_08_55_27.mes was wrote succesfuly
Exception in thread "Thread-4" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:886)
    at java.util.ArrayList$Itr.next(ArrayList.java:836)
    at util.WriteMessages.run(WriteMessages.java:42)
    at java.lang.Thread.run(Thread.java:745)

但是,当我删除这段代码时:

try (OutputStream os = new FileOutputStream(file);){
    m.writeTo(os);
    System.out.println("File " + file.getName() + " was wrote succesfuly");
} catch (IOException | MessagingException ex) {
}

不会出现异常。我认为这个问题已经解决了,但我找不到如何。请帮我解决这个问题。 感谢。

4 个答案:

答案 0 :(得分:1)

我怀疑另一个线程正在访问列表,而此线程正在迭代列表中的消息。这是因为列表引用是共享的,并在其构造函数中传递给线程。

尝试在此对象或其他线程中使用列表对象时进行同步。您可以使用同步列表:

List<Message> messageList = Collections.synchronizedList(list);

在此之后,你仍然需要在迭代列表时进行同步(这实际上是这里最重要的事情,以避免ConcurrentModificationException):

synchronized(messageList) {
    Iterator<Message> iter = messageList.iterator();
    while (iter.hasNext()) {
        ...
    }
}

答案 1 :(得分:1)

在并发环境中,请考虑使用CopyOnWriteArrayList而不是简单ArrayList。当您开始迭代它时,您将迭代迭代开始时列表的内容。通常是那种期望的行为。使用Collections.synchronizedList实际上无法帮助阻止ConcurrentModificationException,并且可能会降低您的应用响应速度。

答案 2 :(得分:0)

您应该能够通过同步产生此线程的方法的访问权来解决它。

答案 3 :(得分:0)

我认为可能会导致您使用其他线程中的消息修改列表,并且由于ArrayList不是线程安全的,您应该考虑另一个List实现。
关于线程安全实现,您可以阅读更多at this post.