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:
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?
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;
}
}
}
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?
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
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.
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.
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.
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.
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,
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
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
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));
}
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;
}
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;
}
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,
ASKER
Any idea?
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());
}
}
}
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:
I also changed
to
Can you please give me an idea why the GUI still freezes?
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);
I also changed
ExecutorService checkExecutor = Executors.newFixedThreadPool(5);
to
ExecutorService checkExecutor = Executors.newSingleThreadExecutor();
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.
ASKER
Sure.
ASKER
Here is my code:
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?