java - 获取一个 ConcurrentModificationException 聊天程序

标签 java chat concurrentmodification

<分区>

我在调用 send() 方法时遇到了 ConcurrentModificationException。我只是访问数据,没有修改,所以我不确定问题出在哪里。有什么建议吗?

public class chatServer{

public static LinkedList<serverListener> threadList = new LinkedList<serverListener>();
public static ListIterator<serverListener> li = threadList.listIterator();

public static void main (String [] args)throws IOException{
    ServerSocket incoming = new ServerSocket(58667); //create new ServerSocket
    Socket servSock;
    BufferedReader buffRead;
    while(true){
        servSock = incoming.accept(); //accept incoming connections from clients
        serverListener c1 = new serverListener(servSock); //create a new chat listener object, passes in servSock socket
        c1.start();
        threadList.addLast(c1);
    }//while(running)
    //incoming.close();
}//main

public static synchronized void send(String m) throws IOException{
    while(li.hasNext()){
        li.next().getOS().writeBytes(m);
    }//while
}//send

public static synchronized void removeClient(DataOutputStream d){
    while(li.hasNext()){
        if (li.next().getOS()==d){
            li.remove();
        }//if
    }//while
}//removeClient
}//chatServer

public class serverListener extends Thread{
private Socket sock; //socket used to communicate (set from passed in value)
private static String incoming; //string to store incoming message
private BufferedReader dataIn; //BufferedReader to read input message
private static DataOutputStream dataOut; //data stream to send message

//chatListener constructor, accepts socket as parameter 
public serverListener(Socket s) throws IOException{
    sock = s; //sets sock to parameter value s
    dataIn = new BufferedReader(new InputStreamReader(sock.getInputStream())); //creates input stream reader from socket sock
    dataOut = new DataOutputStream(sock.getOutputStream()); //creates a new output stream from sock
}//listen constructor

//server listener thread, receives messages from connected client, runs until EXITEXIT is received
public void run(){
    do{
        try{
            setMessage(dataIn.readLine());} //read incoming message, store value in incoming string
        catch(IOException e){ //catches error where a message is unable to be read
        }

        if(getMessage().equals("EXITEXIT")){ //if incoming message is EXITEXIT, set running to false, will not print value
            chatServer.removeClient(dataOut);
            try {
                chatServer.send("Client has left");
            } catch (IOException e) {
            }
        } else
            try {
                chatServer.send(getMessage());
            } catch (IOException e) {
            } //send message to synchronized print method
    }while(true); //loop until isRunning is false
}//run


public static DataOutputStream getOS(){
    return dataOut;
}

private static void setMessage(String m){
    incoming = m;
}
private static String getMessage(){
    return incoming;
}
}//public chatListener

一切正常,直到客户端发送消息并调用发送方法。

更新我最终使用了一个 for 循环:

public static synchronized void send(String m, DataOutputStream d) throws Exception{
    for (int i=0; i<threadList.size(); i++){
        try{
            if(threadList.get(i).getOS()!=d)
                threadList.get(i).getOS().writeBytes(m+'\n');
        }catch(Exception e){}
    }//for
}//send

最佳答案

简而言之,这是因为您修改了一个列表而没有使用它的迭代器。

在这里,您创建一个列表并获取它的迭代器:

public static LinkedList<serverListener> threadList = new LinkedList<serverListener>();
public static ListIterator<serverListener> li = threadList.listIterator();

在这里,您在不使用其迭代器的情况下对列表进行了结构性修改:

while(true){
    servSock = incoming.accept(); //accept incoming connections from clients
    serverListener c1 = new serverListener(servSock); //create a new chat listener object, passes in servSock socket
    c1.start();
    threadList.addLast(c1);
}//while(running)

因此,下次您调用 li.next() 时,您将得到一个 ConcurrentModificationException

来自 LinkedList javadoc(强调我的):

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the Iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

关于java - 获取一个 ConcurrentModificationException 聊天程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23772782/

相关文章:

java - 迭代器但仍然 ConcurrentModificationException

java - android :name attribute do? 是什么意思

java - 使用仅应用程序身份验证获取推文的 Twitter API 返回 HTTP 状态代码 401

javascript - 如何保护聊天消息免受中间人攻击(PHP、JavaScript)

java - 尝试在 android studio 中制作一个聊天应用程序,但我无法附加文本

java - foreach 循环中的 ConcurrentModificationException

java - 在 Java 中从 ArrayList 中删除对象时出错 [Eclipse]

java - 爬行amazon.com

java - Android Google Maps API,防止在屏幕方向更改时重新加载/重绘 map

android - 在 android 中重复执行任务的最佳方法是什么? (例如 :- Refreshing scores, 更新用户界面)