Java 获取ConcurrentModificationException聊天程序

Java 获取ConcurrentModificationException聊天程序,java,chat,concurrentmodification,Java,Chat,Concurrentmodification,调用send()方法时,我得到一个ConcurrentModificationException。我只访问数据,没有修改,所以我不确定问题出在哪里。有什么建议吗 public class chatServer{ public static LinkedList<serverListener> threadList = new LinkedList<serverListener>(); public static ListIterator<serverListene

调用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
公共类聊天服务器{
public static LinkedList threadList=new LinkedList();
公共静态ListIterator li=threadList.ListIterator();
公共静态void main(字符串[]args)引发IOException{
ServerSocket incoming=新的ServerSocket(58667);//创建新的ServerSocket
插座插座;
缓冲读取器buffRead;
while(true){
servSock=incoming.accept();//接受来自客户端的传入连接
serverListener c1=new serverListener(servSock);//创建一个新的聊天侦听器对象,传入servSock套接字
c1.开始();
threadList.addLast(c1);
}//(跑步时)
//incoming.close();
}//主要
公共静态同步无效发送(字符串m)引发IOException{
while(li.hasNext()){
li.next().getOS().writeBytes(m);
}//当
}//发送
公共静态同步void removeClient(DataOutputStream d){
while(li.hasNext()){
if(li.next().getOS()==d){
li.remove();
}//如果
}//当
}//移除客户
}//聊天服务器
公共类serverListener扩展线程{
私有套接字sock;//用于通信的套接字(根据传入值设置)
私有静态字符串传入;//用于存储传入消息的字符串
private BufferedReader dataIn;//用于读取输入消息的BufferedReader
私有静态DataOutputStream dataOut;//要发送消息的数据流
//chatListener构造函数,接受套接字作为参数
公共服务器侦听器(套接字)引发IOException{
sock=s;//将sock设置为参数值s
dataIn=new BufferedReader(new InputStreamReader(sock.getInputStream());//从套接字sock创建输入流读取器
dataOut=newdataoutputstream(sock.getOutputStream());//从sock创建新的输出流
}//侦听构造函数
//服务器侦听器线程,从连接的客户端接收消息,运行直到收到EXITEXIT
公开募捐{
做{
试一试{
setMessage(dataIn.readLine());}//读取传入消息,将值存储在传入字符串中
catch(IOException e){//捕获无法读取消息的错误
}
if(getMessage().equals(“EXITEXIT”){//如果传入消息是EXITEXIT,则将running设置为false,则不会打印值
removeClient(数据输出);
试一试{
发送(“客户端已离开”);
}捕获(IOE异常){
}
}否则
试一试{
发送(getMessage());
}捕获(IOE异常){
}//向同步打印方法发送消息
}while(true);//循环直到isRunning为false
}//跑
公共静态数据输出流getOS(){
返回数据输出;
}
私有静态void setMessage(字符串m){
输入=m;
}
私有静态字符串getMessage(){
返回输入;
}
}//公共聊天听众
在客户端发送消息并调用send方法之前,一切都很正常

更新我最终使用了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 synchronized void send(字符串m,DataOutputStream d)引发异常{

简而言之,对于(inti=0;i,这是因为您修改了一个列表而没有使用它的迭代器

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

public static LinkedList<serverListener> threadList = new LinkedList<serverListener>();
public static ListIterator<serverListener> li = threadList.listIterator();
因此,下次调用
li.next()
,您将得到一个
ConcurrentModificationException

LinkedList
javadoc(我的重点):

此类迭代器和listIterator方法返回的迭代器故障快速:如果在创建迭代器后的任何时间以任何方式(除迭代器自己的remove或add方法外)修改列表的结构,迭代器将抛出
ConcurrentModificationException
。因此,在在并发修改中,迭代器快速而干净地失败,而不是在将来的不确定时间冒任意、不确定行为的风险


谢谢!实际上我只是使用for循环来遍历列表。但是下次我会知道的。
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)