2

我无法在我正在编写的一个简单的 UDP 聊天客户端上运行并发,这一切都运行良好,直到我尝试将新联系人添加到存储在 Peer 中的传出消息列表中,它会引发 CurrentModificationException,有人可以帮助我了解在哪里我走错了吗?

这是我的课

    import java.net.*;
import java.util.*;
import java.io.*;

public class Chatter {

   public static class ReceiveMess extends Thread{ 

   DatagramSocket ds;   
   public ReceiveMess(DatagramSocket s){
        ds = s;
    } 

     byte[] Rbuf = new byte[1000];
     DatagramPacket Rdgp = new DatagramPacket(Rbuf, Rbuf.length); 

        public synchronized void run() {
            try{
                while (true){
                    for(Peer p : Peer.PeerList){
                        ds.receive(Rdgp);
                        String rcvd = new String(Rdgp.getData(), 0, Rdgp.getLength()) + ", from address: "
                        + Rdgp.getAddress() + ", port: " + Rdgp.getPort();
                        System.out.println(rcvd);
                    }
                }
            }
            catch(IOException e) {
                System.out.println(e);
            }
        }
    }

    public static class SendMess extends Thread{

    DatagramSocket ds;  

    public SendMess(DatagramSocket s){
            ds = s;
    }


    int SPORT = 40080;
    byte[] Sbuf = new byte[1000];
    DatagramPacket Sdgp = new DatagramPacket(Sbuf, Sbuf.length);

        public synchronized void run() {
            try{
                while (true) {
                    BufferedReader consR = new BufferedReader(new InputStreamReader(System.in));
                    String MessOut = consR.readLine();
                    if(MessOut.startsWith("/NEW")){
                        try{
                            String[] splitArray = MessOut.split(" ");
                            String newIP = (splitArray[1]);
                            Peer p = new Peer(newIP);
                            System.out.println(newIP + " added to the contacts list");
                            continue;
                        }
                        catch(Exception e){
                            System.out.println("Please format NEW IP address's as NEW XXX.XXX.XXX.XXX");
                            continue;
                        }
                    }
                    else{
                        Sbuf = ("Server Said: " + MessOut).getBytes();
                        for(Peer p : Peer.PeerList){
                            DatagramPacket out = new DatagramPacket(Sbuf, Sbuf.length, p.IP, SPORT);
                        ds.send(out);}
                    }
                }
            }
            catch(IOException e) {
                System.out.println(e);
            }
        }
    }

    public static void main(String [] args){

      try{  
        for(String s : args){
            String address = s;
            Peer peer = new Peer(address);
        }

      int PORT = 40080;
      DatagramSocket ds = new DatagramSocket(PORT);

      Peer.PrintList();    

        SendMess sendmess = new SendMess(ds);
        sendmess.start();        
        ReceiveMess receivemess = new ReceiveMess(ds);
        receivemess.start();  
    }
    catch(Exception e){
        System.out.println(e);
    }
    }
}

And my peer class,

        import java.net.*;
    import java.util.*;

    public class Peer{



        InetAddress IP;
        static List<Peer> PeerList = new LinkedList<Peer>();

        Peer(String clientAddress){ 
            try{
                IP = IP.getByName(clientAddress);
                AddToList(this);
            }
            catch(UnknownHostException e){
                System.out.println(e.toString());
            }
        }   

        public synchronized void AddToList(Peer peer){
            PeerList.add(this);
        }

        public List<Peer> GetList(){
            return PeerList;
        }

        public static void PrintList(){
            for(Peer p : PeerList){
            System.out.println(p.IP.toString());
            }   
        }
    }
4

2 回答 2

0

方法的关键字synchronized等价于:

public void run() {
    synchronized(this) {
     ...
    }
}

在您的同步方法中,this是一个不同的对象(ReceiveMessSendMessPeer,因此没有什么可以阻止这些方法同时运行。请改用普通显示器(Chatter.class最方便)。

也就是说,synchronizedfor 方法不是全局的,它只是在this. 我鼓励您在继续之前至少阅读整首曲目

于 2013-09-13T10:04:31.470 回答
0

所以你的问题是...

您有一个循环,ReceiveMess其中迭代Peer. 同时,SendMess您正在创建Peer. 当创建 的新实例时,Peer这会向PeerList. 这会导致 CME 在ReceiveMess.

我建议您删除所有synchronized关键字,因为它们没有为您做任何事情,并从Peer.getList. 这意味着当一个线程正在迭代列表时,即使另一个线程修改了Peers迭代线程的列表也不会受到影响。然后,迭代线程将在 while 循环的下一次迭代中看到更新。

执行此操作的一种机制是使用 aCopyOnWriteArrayList或 Guava 的ImmutableList.Builder.

CopyOnWriteArrayList

不可变列表生成器

于 2013-09-13T10:24:12.047 回答