Link to home
Start Free TrialLog in
Avatar of Tolgar
Tolgar

asked on

How to remove elements from a hashmap in Java?

Hi,
I am working on a GUI and I do concurrent programming to run some external commands without causing the GUI to freeze.

Actually, my question is more general about one of the control points in my code:

ExecutorService checkExecutor = Executors.newFixedThreadPool(5);
HashMap<Integer, Future> futures = new HashMap<Integer,Future>(fileData.length);

for (int j = 0; j < fileData.length; j++){
                    SOME CODE IN HERE

                    CheckRunner myRunner = new CheckRunner();
                    myRunner.setCommand(perlCmd);
                    futures.put(j, checkExecutor.submit(myRunner));  
}


boolean exitLoop = false;
boolean newRun = true;
while(true && exitLoop == false) {
    for (Future f : futures.values()) {
            if (f.isDone()) {
                try {
                        List<CheckDetail> checkDetails = (List<CheckDetail>) f.get();
                        checkDetailsAll.addAll(checkDetails); 
                        Gui.populateResultsTable(checkDetails,shell,table,titles, newRun);
                        newRun = false;
                     } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                     } catch (ExecutionException e) {
                        // TODO Auto-generated catch block
                       e.printStackTrace();
                     }
                     if (!futures.isEmpty())
                         futures.remove(f);
                     if (futures.isEmpty())
                        exitLoop = true;
             }
     }
 }

Open in new window


The problem is the exitLoop never becomes true because futures.isEmpty() never becomes true (Line 33). And the reason is I think futures.remove(f)  (Line 31) does not work as expected.

As a result of this, the while loop run infinitely.

so, my question is why futures.remove(f) does not remove the elements of futures and eventually why futures never become empty?
Avatar of Tolgar
Tolgar

ASKER

I changed the my code as the following my my code still goes in an infinite loop because iter.next().getValue().isDone() never becomes true:

Here is my code:

            ExecutorService checkExecutor = Executors.newFixedThreadPool(5);
            HashMap<Integer, Future> futures = new HashMap<Integer,Future>(fileData.length);

            for (int j = 0; j < fileData.length; j++){
               SOME CODE IN HERE
               
               perlCmd = batchFileCmd;
               CheckRunner myRunner = new CheckRunner();
               myRunner.setCommand(perlCmd);
               futures.put(j, checkExecutor.submit(myRunner));  

              }

            boolean exitLoop = false;
            boolean newRun = true;
            Iterator <Map.Entry<Integer, Future>> iter = futures.entrySet().iterator();
            while(true && exitLoop == false) {
                //for (Future f : futures.values()) {
                while (iter.hasNext()) {
                    
                    //Disable the runCheck button in the 2nd tab 
                    //to prevent the user from using it
                    //while the other processes are running.
                    Gui.item23.setEnabled(false); 
                    if (iter.next().getValue().isDone()) {
                        Entry<Integer, Future> entry = iter.next();
                        try {
                            List<CheckDetail> checkDetails = (List<CheckDetail>) entry.getValue().get();
                            checkDetailsAll.addAll(checkDetails); 
                            Gui.populateResultsTable(checkDetails,shell,table,titles, newRun);
                            newRun = false;
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                            iter.remove();

                    }
                }
                exitLoop = true;
            }

Open in new window



Line 25 in this code never becomes true. WHY? I know that the other process is done and I can see its exit code on my console but this never returns true. ANY IDEAS?
SOLUTION
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Tolgar

ASKER

@mccarl: I tried to use the code that you recommended but it didn't work. I assume your initial assumption is correct and this approach does not work. I will post more about the logic that I follow in here. I hope you can show me the right direction:

In Gui.java file, I put the widgets and start the gui.

After I click on one button, this is what happens in the code:

Gui.java This is the main code where I create all the items of the gui.
         
         
public class Gui {

 public static void main(String[] args) throws SQLException, ClassNotFoundException {

        SOME CODE IN HERE

        CustomToolbar custToolBar22 = new CustomToolbar(compTB2, SWT.FLAT, "Next Actions");
                
        item23 = new ToolItem(custToolBar22.getToolBar(), SWT.PUSH);
        item23.setImage(image_navigate_right); item23.setText("Run checks"); item23.setToolTipText("Run the checks against the files you selected");
        item23.addListener(SWT.Selection, toolBarListener);

        SOME MORE CODE IN HERE

Open in new window


ToolbarListener.java
This is the listener. When the user clicks item23 in the gui, the tab should first change and then the other tasks are supposed to take place. In my case, the tabb does not switch even though I execute this line because the gui gets frozen.

        public class ToolBarListener implements Listener {
    

       @Override
       public void handleEvent(Event event) {
        
        SOME CODE IN HERE        

        } else if (toolItem == Gui.item23) {
            Gui.swichTabResults();
            try {
                List<CheckDetail> checkDetails = RunPerl.runCheck();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

           SOME MORE CODE IN HERE

Open in new window



RunPerl.java This is to prepare the command that will be run by using some inputs from the user. Once the perl cmd is set then the executer is supposed to run them in the new thread.

public class RunPerl {

SOME CODE IN HERE

public static List<CheckDetail> runMwcheck() throws IOException {

SOME CODE IN HERE

            ExecutorService checkExecutor = Executors.newFixedThreadPool(5);
            HashMap<Integer, Future> futures = new HashMap<Integer,Future>(fileData.length);
            //int j = 0;
            for (int j = 0; j < fileData.length; j++){
             
                SOME CODE IN HERE

                    perlCmd = batchFileCmd;
                    CheckRunner myRunner = new CheckRunner();
                    myRunner.setCommand(perlCmd);
                    futures.put(j, checkExecutor.submit(myRunner));  
             }

Open in new window


CheckRunner.java:
This is to run the cmd in the other threads. Once it is completed, it will generate an XML file and the xml parser will parse this xml file and it will dump the information into checkDetails.

public class CheckRunner implements Callable<List<CheckDetail>> {
    protected String resultsXML;
    protected String execCmd;
    static List<CheckDetail> checkDetails = null;
    static List<CheckDetail> checkDetailsAll = new ArrayList<CheckDetail>();
    
   public void setCommand(String perlCmd)
   {
       execCmd = perlCmd;
   }
   
   public List<CheckDetail> call() {
      Process check_process = null;
     //get the environment variables
       Map<String, String> env = System.getenv();
       String [] environment = new String[env.size()];
       int i = 0;
       for (Map.Entry<String, String> entry : env.entrySet())
       {
           environment[i] = entry.getKey() + "=" + entry.getValue();
           i++;
       }
       
       Runtime check_runtime = Runtime.getRuntime();
       
       
       try {
           check_process = check_runtime.exec(execCmd, environment);
           } catch (Exception e) {
           System.out.println("error executing " + execCmd);
       }
       

       /* dump output stream */
       InputStream is = check_process.getInputStream();
       BufferedReader reader = new BufferedReader
           ( new InputStreamReader(is));
       String commandLineOutput;
       
       try {
        while ((commandLineOutput = reader.readLine()) != null) {
               Pattern p = Pattern.compile("\\d{8}_\\d{4}_\\d{2}_.*?_check_CodingStandards_ALL_Files.xml");
               Matcher m = p.matcher(commandLineOutput);
               if (m.find()){
                   resultsXML = m.group();                       
               }
               System.out.println(commandLineOutput);
           }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
       System.out.flush();
       /* print final result of process */
       System.err.println("Exit status=" + check_process.exitValue());
       
       String tempDir = null;
       String OS = System.getProperty("os.name").toLowerCase();
       
       if (OS.indexOf("win") >= 0){
           tempDir = "C:/Temp/check";
       } else{
           tempDir = "/tmp/check";
       }
       
       //get the name of the  generated XML from the CLI 
       //and parse it to generate the results table
       String path2ResultsXML = tempDir + "/" + resultsXML;
       new ParseResultsXML().parse(path2ResultsXML);
       checkDetails = new ParseResultsXML().parse(path2ResultsXML);
       return checkDetails;
}

Open in new window


And then back to RunPerl.java code to watch if any process is done. If it is done, then I will populate the results in the results table.

            
            boolean exitLoop = false;
            boolean newRun = true;
            while(true && exitLoop == false) {
                for (Future f : futures.values()) {
                                 
                    //Disable the runCheck button in the 2nd tab 
                    //to prevent the user from using it
                    //while the other processes are running.
                    Gui.item23.setEnabled(false);
                        try {
                            List<CheckDetail> checkDetails = (List<CheckDetail>) f.get();
                            checkDetailsAll.addAll(checkDetails); 
                            Gui.populateResultsTable(checkDetails,shell,table,titles, newRun);
                            newRun = false;
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                            futures.remove(f);
                    }
                }
                exitLoop = true;   
            return checkDetailsAll;
        }

Open in new window


So, this is the skeleton of my code that is supposed to run a process in another thread. And as the process is completed, I will get its output which is checkDetails in this code and I will populate the results by calling populateResultsTable in the Gui.java code.

Even though, this code can run the process in the new thread (which I can see the output in the console), it does not update the table using the code I shared with you in here, the UI still freezes.

Can you please tell me what is wrong in here?

I can share more code if it helps but this is almost the entire code that does the work for this task.

Thanks,
Avatar of Tolgar

ASKER

Any idea?
Avatar of Tolgar

ASKER

I made this change in the while loop, but this still does not work:

            while(true && exitLoop == false) {
                
                for (Entry<String, Future> entry  : futures.entrySet()) {
                    Future<List<CheckDetail>> f = entry.getValue();
                        try {
                            List<CheckDetail> checkDetails = f.get(1, TimeUnit.MILLISECONDS);
                            
                            if (checkDetails != null) {
//                                fileName = checkDetails.get(0).getFileName();
//                                fileName.replaceAll(sandboxLocation, "");
//                                fileName = fileName + "=" + f;
                                checkDetailsAll.addAll(checkDetails); 
                                Gui.populateResultsTable(checkDetails,shell,table,titles, newRun);
                                newRun = false;
                            }
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (TimeoutException e) {
                           ;
                        }

                        if (futures.isEmpty())
                           exitLoop = true;
                        
                        String key = null;
                        if (!futures.isEmpty()){           
                            futures.remove(entry.getKey());
                        }                       
                    }                
                }

Open in new window

Avatar of Tolgar

ASKER

Finally, I made this change and now the code works fine but the GUI still freezes while it is processing:

Here is the code:

            boolean exitLoop = false;
            boolean newRun = true;
            
            //Disable the runCheck button in the 2nd tab 
            //to prevent the user from using it
            //while the other processes are running.
             Gui.item23.setEnabled(false);
             String fileName = null;
            while(true && exitLoop == false) {
                
            HashMap<String, Future> tempFutures = futures;   
            ArrayList<String> keyList = new ArrayList<String>();
            
            for (Entry<String, Future> entry  : tempFutures.entrySet()) {
                Future<List<CheckDetail>> f = entry.getValue();
                    try {
                        List<CheckDetail> checkDetails = f.get(1, TimeUnit.MILLISECONDS);
                        
                        if (checkDetails != null) {
                            keyList.add(entry.getKey());
                            checkDetailsAll.addAll(checkDetails); 
                            Gui.populateResultsTable(checkDetails,shell,table,titles, newRun);
                            newRun = false;
                        }
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (TimeoutException e) {
                       ;
                    }
                }    

            if (!futures.isEmpty()){             
                for (String key : keyList) {
                    futures.remove(key);
                }                        
            }
            
            if (futures.isEmpty())
               exitLoop = true;
            }

            checkExecutor.shutdown();
            Gui.item23.setEnabled(true);

Open in new window


I also changed

            ExecutorService checkExecutor = Executors.newFixedThreadPool(5);

Open in new window


to

           
ExecutorService checkExecutor = Executors.newSingleThreadExecutor();

Open in new window


Can you please give me an idea why the GUI still freezes?
Since this question has changed from the original (and that I see you have already started a new one), this one should be resolved and we will continue discussion in the other.
Avatar of Tolgar

ASKER

Sure.