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?
TolgarAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

TolgarAuthor Commented:
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?
0
krakatoaCommented:
The doc says you can call remove() only once per call to next(). In your while loop, you call next() twice. Not saying that's your entire problem, but it doesn't look like it helps.
0
mccarlIT Business Systems Analyst / Software DeveloperCommented:
I do concurrent programming to run some external commands without causing the GUI to freeze
This code by itself won't give you your desired result. If I am assuming correctly, that this code is directly in a GUI items event handler, then it doesn't matter that you are using an executor to run the tasks in a separate thread/threads because you then do a busy wait for those tasks to complete which still holds up the thread and won't allow your GUI to be responsive.

If I am incorrect in my assumption, and you DO actually have this code itself running in it's own thread (that is not shown here), then that might be ok. If so, I would change your "while(true && exitLoop == false)" loop to something more like this...
for (Future f : futures.values()) {
                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();
                     }
     }

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

TolgarAuthor Commented:
@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,
0
TolgarAuthor Commented:
Any idea?
0
TolgarAuthor Commented:
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

0
TolgarAuthor Commented:
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?
0
mccarlIT Business Systems Analyst / Software DeveloperCommented:
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.
0
TolgarAuthor Commented:
Sure.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.