java - 如何同步两个方法

标签 java multithreading collections concurrency

我有以下 Java 聊天服务器应用程序代码 -

public synchronized List<ChatMessage> getMessages(int messageNumber) {
    return messages.subList(messageNumber + 1, messages.size());
}

public synchronized int addMessage(ChatMessage c) {
    messages.add(c);
    return messages.size()-1;
}

我有以下测试代码 -

public static void main(String[] args) {
    final ChatRoom c = new ChatRoom();
    Thread user1 = new Thread(new Runnable() {
        public void run() {
            for(int i=0;i<1000;i++) {
                c.addMessage(new ChatMessage());
                c.getMessages(0);
            }
        }
    });
    Thread user2 = new Thread(new Runnable() {
        public void run() {
            for(int i=0;i<1000;i++) {
                c.addMessage(new ChatMessage());
                c.getMessages(0).size();
            }
        }
    });
    user1.start();
    user2.start();
}

我收到 ConcurrentModificationException。

这怎么可能?

最佳答案

How is this possible?

您的 getMessages 方法仅返回原始列表上的 View 。它不会创建列表的副本。因此,一个线程正在使用列表上的 View ,而另一个线程则修改列表 - 此时,您会遇到异常。

来自 List.subList 的文档:

The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)

目前尚不清楚您真正想要实现的目标是什么,但从根本上讲,您不能使用 subList 神奇地创建线程安全列表:)

关于java - 如何同步两个方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10086527/

相关文章:

java - 使用导出变量在Java程序中调用bash脚本

Eclipse 中的 Java 属性 UTF-8 编码

java - 等同于带有多个字符定界符的 StringTokenizer

collections - Java8 : Use filters/predicates along with disjunction

java - 实现 CharSequence 以便使用 String.join?

java - 在 Maven 项目中找不到 ImmutableMap

java - 先前完成后添加新订阅

c++ - 为什么我的编译器不能识别 #include <thread> (c++)?

c# - 具有批量生产者的生产者/消费者模式

java - 在线程java中访问变量