运行两个线程时出现ConcurrentModificationException问题

3

目前,我正在开发一个支持多客户端的服务器,我有一个线程检查是否有任何套接字连接到给定的端口,然后将它们添加到一个arraylist中,另一个线程使用该arraylist来更新需要处理的客户端信息(更新信息、检查DataInputStream、通过服务器发送文本)等等。

客户端代码:

public class Loop implements Runnable{

ArrayList<ClientInstance> clientsConnected = new ArrayList<ClientInstance>();

@Override
public void run() {
    while(true) {
        checkInputStream();
    }

}

public void checkInputStream() {
    for (ClientInstance s : clientsConnected) {
        s.checkInputStream();
    }
}

服务器代码:

public synchronized void waitForClient() {
    try {
        System.out.println("Waiting for client on port: "
                + serverSocket.getLocalPort());
        Socket client = serverSocket.accept();
        System.out.println("Client Connected! " + client.getInetAddress());
        loop.getClientsConnected().add(new ClientInstance(client));
        System.out.println("Client added to clients connected! ");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

但是,当我运行服务器并连接一个客户端时,它可以正常工作。但是,当我连接另一个客户端时,就会出现以下问题:

Exception in thread "Thread-1" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)

我该怎么办?

3个回答

1
使用 CopyOnWriteArrayList 来修复它。
List<String> myList = new CopyOnWriteArrayList<String>();     
myList.add("1");
myList.add("2");
myList.add("3");myList.add("4");myList.add("5");
System.out.println("List Value:"+value);

        Iterator<String> it = myList.iterator();
        while(it.hasNext()){
            String value = it.next();                    

            if(value.equals("3")){
                myList.remove("4");
                myList.add("6");
                myList.add("7");
            }
        }
        System.out.println("List Size:"+myList.size());

输出:

List Value:1
List Value:2
List Value:3
List Value:4
List Value:5
List Size:6

提示:-

  1. 并发集合类可以避免修改时出现“ConcurrentModificationException”异常。

  2. 在使用“CopyOnWriteArrayList”时,迭代器不会适应列表中的更改,而是在原始列表上工作。


1
这是因为您正在修改ArrayList(即在waitForClient()方法中添加列表元素),同时在checkInputStream()方法中对其进行迭代。
如@Arjit所提到的,建议使用CopyOnWriteArrayList而不是ArrayList。

在checkInputStream方法中创建一个新的Collections.unmodifiableList。 - Arjit
使用CopyOnWriteArrayList - 并发集合类可以避免ConcurrentModificationException而进行修改。 - Arjit
1
@Naman - 迭代器不会起作用 - 因为它只允许删除方法,但如果您正在向其中添加元素,则会抛出ConcurrentModificationException异常。 - Arjit
哦,我明白了。谢谢通知。我会更新代码的。 - Naman Gala
@FireRaven101,请问您能否接受Arjit所给出的答案。 - Naman Gala
显示剩余4条评论

0

尽管您为方法waitForClient同步(在此处插入元素),但您没有为方法checkInputStream进行锁定。

您可以使用CopyOnWriteArrayList代替ArrayList。这已经在问题"避免返回列表时可能出现的并发问题"中得到了回答。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接