private void processMulti(MulticastMessage multiMsg) {
        String destGroup = multiMsg.getSrcGroup();
        ArrayList<String> memberList = groupList.get(destGroup).getMemberList();
        MessageKey curKey = new MessageKey();

        // If we receive a real multicast message
        if(!multiMsg.getKind().equals("Ack")) {
            String localName = multiMsg.getDest();
            //System.out.println("Get a multicast message, from " +
            //                   multiMsg.getSrc() + " destGroup: " + destGroup + multiMsg);

            curKey.setDestGroup(multiMsg.getSrcGroup());
            curKey.setSrc(multiMsg.getSrc());
            curKey.setNum(multiMsg.getNum());

            // If it is a new message, add it to holdBackQueue
            if(!holdBackQueue.containsKey(curKey)) {
                holdBackQueue.put(curKey, multiMsg);
            }

            // Send Ack message to every group member, exclude itself
            for(String member : memberList) {
                if(!member.equals(localName)) {
                    MulticastMessage ackMsg = new MulticastMessage(member, "Ack", curKey);
                    ackMsg.setSrc(localName);
                    ackMsg.setTimeStamp(multiMsg.getTimeStamp());
                    ackMsg.setSeqNum(multiMsg.getSeqNum());
                    ackMsg.setSrcGroup(((MulticastMessage) multiMsg).getSrcGroup());
                    ackMsg.setNum(((MulticastMessage) multiMsg).getNum());
                    //System.out.println("Send Ack message from " + ackMsg.getSrc() + ", to: " + ackMsg.getDest());
                    MessagePasser.getInstance().checkRuleAndSend(ackMsg);
                }
            }
        }
     // If we receive an Ack message
        else {
            //System.out.println("Get Ack message, from " + multiMsg.getSrc() + " to: " + multiMsg.getDest() + multiMsg);
            // Update ack record map
            curKey = (MessageKey) multiMsg.getData();
            if(acks.containsKey(curKey)) {
                acks.get(curKey).add(multiMsg.getSrc());
            }
            else {
                HashSet<String> tmp = new HashSet<String>();
                tmp.add(multiMsg.getSrc());
                acks.put(curKey, tmp);
            }
        }

        // If we get enough ack for this message
        if((acks.get(curKey) != null) &&
           (acks.get(curKey).size() == memberList.size() - 1) &&
           (holdBackQueue.containsKey(curKey))) {
            //String msgKey = curKey.getSrc() + curKey.getDestGroup();
            deliver(curKey);
        }
    }