当我调用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
在客户端发送消息并调用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
答案 0 :(得分:3)
简而言之,因为你修改了一个列表而没有使用它的迭代器。
在这里,您创建一个列表并获取其迭代器:
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(强调我的):
此类的iterator和listIterator方法返回的迭代器是 fail-fast :如果在创建迭代器后的任何时候对列表进行结构修改,无论如何除非通过Iterator自己的remove或add方法,迭代器将抛出
ConcurrentModificationException
。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒着任意的,非确定性行为的风险。