calling a second method while one method call is still in progress causes program to crash

StackOverflow https://stackoverflow.com/questions/23636426

  •  21-07-2023
  •  | 
  •  

سؤال

I am having some trouble with a couple of methods in my program: I have a method that is called when the user clicks a start button on the GUI. This method will receive all of the network traffic currently being sent/ received over the network, and display information about it to the user. The user can stop this method being called by clicking the stop button. This method currently looks like this:

public static void retrieveFilteredPdu(){

    /*Try/Catch block copied from 'receivePdu()' method in EspduReceiver.java on 07/05/2014
     * Now edit it so that it will receive all PDUs, but only display the ones matching the filter values in the top JTextArea */
    try{
        /*Specify the socket to receive the data */
        EspduReceiver.socket = new MulticastSocket(EspduSender.PORT);
        EspduReceiver.address = InetAddress.getByName(EspduSender.DEFAULT_MULTICAST_GROUP);
        EspduReceiver.socket.joinGroup(EspduReceiver.address); 

        //stopCapture = false;

        /*Loop infinitely, receiving datagrams */
        while(true){
            /*First, set the value of the 'stopCapture' boolean to 'false', in case it has previously been set to true during the life of
             * the program */
            /*stopCapture = false; /*For some reason, if I do this here, clicking the 'Get site' button causes the program to start receiving
            PDUs again, and you are not able to stop it without manually shutting down the program. Possibly because I am infinitely
            setting the value of 'stopCapture' to false?*/

            byte buffer[] = new byte[EspduReceiver.MAX_PDU_SIZE];
            EspduReceiver.packet = new DatagramPacket(buffer, buffer.length);

            EspduReceiver.socket.receive(EspduReceiver.packet);

            Pdu pdu = EspduReceiver.pduFactory.createPdu(EspduReceiver.packet.getData()); /*Moved this line to the top of the class to declare as global variable (29/04/2014) */

            if(pdu != null){
                System.out.print("Got PDU of type: " + pdu.getClass().getName());
                if(pdu instanceof EntityStatePdu){
                    EntityID eid = ((EntityStatePdu)pdu).getEntityID(); 
                    Vector3Double position = ((EntityStatePdu)pdu).getEntityLocation(); 
                    System.out.println(" EID:[" + eid.getSite() + ", " + eid.getApplication() + ", " + eid.getEntity() + "] ");
                    System.out.println("Location in DIS coordinates: [" + position.getX() + ", " + position.getY() + ", " + position.getZ() + "] ");
                    /*Add PDU to ArrayList of PDUs */
                    EspduReceiver.espdu.add(pdu);
    /*              System.out.println(" PDU added to arrayList. "); 
                    System.out.println(espdu); /*This is printing out the actual DIS messages (i.e. edu.nps.moves.dis.EntityState...),
                    maybe try adding the 'eid.getSite()', etc to an ArrayList instead. Use Associative arrays/ map/ hashmap */

                    EspduReceiver.entitySite.add(eid.getSite());
                    System.out.println("Entity Site added to ArrayList from Filter.retrieveFilteredPdu() ");
                    EspduReceiver.entityApplication.add(eid.getApplication());
                    System.out.println("Entity Application added to ArrayLIst. ");
                    EspduReceiver.entity.add(eid.getEntity());
                    System.out.println("Entity ID added to ArrayList");

                    /*Check that everything is actually in the ArrayLists 
                    for(int i : entity){ /*Substituted 'entity' with 'entitySite' and 'entityApplication'- values are all printed correctly. 
                    System.out.println(i);
                    } */

                    /*07/05/2014
                     * Write a method that will only append the PDUs that match the filter values to the text area,
                     * call that method here. */



                    /*Now append each PDU to the text area */
                    Gui.displayFilteredOutput.append("\n");
                    Gui.displayFilteredOutput.append("EID: [" + eid.getSite() + ", " + eid.getApplication() + ", " + eid.getEntity() + "]. ");
                    Gui.displayFilteredOutput.append("Location in DIS coordinates: [" + position.getX() + ", " + position.getY() + ", " + position.getZ() + "] ");

                    /*Append every PDU that matches the filter criteria to the displayFilteredOutput JTextArea 
                    Gui.displayFilteredOutput.append("\n");
                    Gui.displayFilteredOutput.append("EID: [" + eid.getSite() + ", " + eid.getApplication() + ", " + eid.getEntity() + "]. ");
                    Gui.displayFilteredOutput.append("Location in DIS coordinates: [" + position.getX() + ", " + position.getY() + ", " + position.getZ() + "] "); */


                } else if(!(pdu instanceof EntityStatePdu)){
                    System.out.println("There are no PDUs currently being received.");
                }
                System.out.println();
            }
            Thread.sleep(1000);
            /*Try adding a boolean to allow me to stop the capture by clicking 'stop' button- Look on stackoverflow */
            boolean queryStopCapture =  EspduReceiver.stopCapture;
            if(queryStopCapture ==  true){
                System.out.println("Break clause in 'queryStopCapture' if statement in EspduReceiver.java has been called. ");
                break; /*Use a call to receivePdu() to populate the second JTextArea, but don't let it call a 'break' clause at all. 
             *          Find some other way of adding a 'break' to the output displayed in the first JTextArea (01/05/2014)
             *          Maybe add this code to receivePdu() call in ActionListener instead of here.
             */
            } 
        } /*end while */
    } /*end try */
    catch(Exception e){
        System.out.println(e);
        e.printStackTrace();
        System.out.println("Error in retrieveFilteredPdu() method. ");
        /*09/04/2014 @ 17:100
         * If this exception gets called, presumably it either means that pdu is not an instance of EntityStatePdu, or
         * that pdu does not actually hold a packet.  */
    }

}

I have another method, which, in theory, should display information about only the network traffic which has attributes matching some values set by the user. This method is called when the user clicks the 'Filter' button on the GUI. The method currently looks like this:

public static void filterPDUs(){
//  if(EspduReceiver.startCapture == true){
        /*If EspduReceiver.startCapture is true, then the program is already receiving PDUs, so now I need to set it to only display the ones that
         * match the filter criteria. Do this by checking the PDU attributes against the filter values before printing- if they match, then print,
         * if not, don't. */
        if((EspduReceiver.startCapture == true) && (EspduReceiver.stopCapture == false)){
            /*Get the size of the sitesToBeFiltered ArrayList, and store in a variable. Will need to update the variable with every iteration
             * of the loop, because the ArrayList will keep growing as long as the capture is running. */
            int sitesToBeFilteredSize = sitesToBeFiltered.size();
            int matchingSitesIterator = 0;
            /*First, check if site filter value matches the PDU's site, if it does, then check Application, if it matches again, then check ID.
             * If at any point it doesn't match, exit the while loop. */
            while(matchingSitesIterator < sitesToBeFilteredSize){
                System.out.println("SitesToBeFiltered.size() = " + sitesToBeFilteredSize);
                if(sitesToBeFiltered.get(matchingSitesIterator) == Filter.filter1Value){
                    if(applicationsToBeFiltered.get(matchingSitesIterator) == Filter.filter2Value){
                        if(IDsToBeFiltered.get(matchingSitesIterator) == Filter.filter3Value){
                            Gui.displayFilteredOutput.append("Matching PDU found: [" + sitesToBeFiltered.get(matchingSitesIterator) + ", " + applicationsToBeFiltered.get(matchingSitesIterator) + ", " + IDsToBeFiltered.get(matchingSitesIterator) + "] ");
                        } else {Gui.displayFilteredOutput.append("Sorry, there were no PDUs found with the specified ID value.");}
                        Gui.displayFilteredOutput.append("Need to display every PDU that had a matching Site & Application here. ");
                    }else {Gui.displayFilteredOutput.append("Sorry, there were no PDUs found with the specified Application value.");}
                    Gui.displayFilteredOutput.append("need to display every PDU that had a matching Site here. ");
                }else {Gui.displayOutput.append("Sorry, there were no PDUs found with the specified Site value.");}
            }
        } else {
            Gui.displayFilteredOutput.append("Do something if EspduReceiver.startCapture is not true, and EspduReceiver.stopCapture is not false");
        }

//  }else if(EspduReceiver.startCapture == false){
        /*If EspduReceiver.startCapture is false, then the program is not receiving PDUs, so I now need to call the method that will receive PDUs, 
         * and display only the ones that match the filter criteria. */
//  }
}

The problem I'm having is that for some reason, if the user clicks the 'Filter' button to display only the PDUs with matching filter criteria, after clicking 'Start' (to call the first method), then the program crashes completely... (i.e. it appears to stop performing the function that it was carrying out, and will not respond to clicks on any buttons or even the 'Close window' button)

If they click 'Filter' after having clicked 'Start' & 'Stop' (i.e. when the first method is not running, then the second method performs its tasks as expected.

It seems that for some reason, calling the second method while the first method is still running causes the program to crash- and I can't work out why this is... can anyone point out what's going wrong here?

Edit

I have the following code in my main method:

public static void main(String[] args){
    SwingUtilities.invokeLater(new Runnable(){
        @Override
        public void run(){
            Gui gui = new Gui();
            gui.setVisible(true);
        }
    });
}
هل كانت مفيدة؟

المحلول

You need to show more of the code, as others have said, but if you're using Swingworkers or other threads to run these methods, then either the methods have to be thread-safe or they need to be synchronized to prevent their execution from being interleaved. If you're directly accessing Swing components outside the event-dispatching thread, then Swing will make demons come out of your nose, so don't do that (there are some special exceptions for some text components, but generally it's prohibited). If you're not sure, stick assert java.awt.EventQueue.isDispatchThread() before every statement that constructs or uses a Swing object, and enable assertions in the runtime system.

نصائح أخرى

I assume Gui is built on Swing. Read the Swing tutorial, and pay attention to the Event Dispatch Thread. I can't see how the Swing portion of you code works, but I'm guessing you are locking up the EDT somehow. A long-running process needs to run in its own thread and use SwingUtilities.invokeLater() to update Swing components, like your text area.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top