I have a GUI-based application that takes in a file and displays it to the user in a table format, gets some input in the form of column annotations and a bunch of parameters. Then it parses the file accordingly and initiates an "analysis".
I just found a deadlock, one I have not encountered before.
Found one Java-level deadlock:
=============================
"RMI TCP Connection(5)-130.235.214.23":
waiting to lock monitor 0x00007fac650875e8 (object 0x0000000793267298, a java.util.logging.ConsoleHandler),
which is held by "AWT-EventQueue-0"
"AWT-EventQueue-0":
waiting to lock monitor 0x00007fac65086b98 (object 0x00000006c00dd8d0, a java.io.PrintStream),
which is held by "SwingWorker-pool-1-thread-3"
"SwingWorker-pool-1-thread-3":
waiting to lock monitor 0x00007fac65087538 (object 0x00000006c001db48, a java.awt.Component$AWTTreeLock),
which is held by "AWT-EventQueue-0"
Essentially there is a parsing error and trying to log it hangs the application altogether. Interestingly logging appears to work normally before and after that particular step..
Here's the part of the code that's relevant for the analysis task:
// Activate progress indicator
frame.getMainFrame().activateInfiGlass();
SwingWorker<Map<Analyte,AnalysisResult>, Void> worker = new SwingWorker<Map<Analyte,AnalysisResult>, Void>() {
@Override
protected Map<Analyte,AnalysisResult> doInBackground() {
try {
// register parameters
param.addParam(AnalysisParams.value_key,descPanel.getValueTypeComboIndex());
param.addParam(AnalysisParams.sepchar_key,descPanel.getSepCharComboIndex());
paramPanel.registerParams();
StringBuilder sb = new StringBuilder("Data preview completed, initiating analysis...");
sb.append(System.lineSeparator())
.append("... column annotations: ")
.append(Arrays.toString(annots));
logger.info(sb.toString() + System.lineSeparator());
// Create dataset; to be passed on to SwingWorker which will
// execute the analysis
ds = new Dataset();
String[] line;
for (int i=0; i < data.length; i++){
line = data[i];
// If ignore button is clicked, skip row..
if(!(Boolean) table.getValueAt(i, 0))
ds.addRow(line, annots); // <-- This step is where the parsing exception occurs
}
System.out.println("Dataset parsed...");
logger.info("Dataset parsing complete "
+ System.lineSeparator()
+ ds.toString()
+ System.lineSeparator());
visualizeDataset();
conserv = new ConcurrencyService(ds, dbMan);
conserv.serve();
} catch (InterruptedException e) {
logger.severe("Concurrency service interrupted"
+ System.lineSeparator()
+ DebugToolbox.getStackTraceAsString(e)
+ System.lineSeparator());
System.err.println("Interrupt exception!!");
}
return conserv.getAnalyzedPaths();
}
@Override
protected void done() {
try{
results = get();
visualizeResults();
}
catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error analysing data: " + why);
} catch (SQLException e) {
e.printStackTrace();
}
logger.info("#DEBUG: Conserv should have been terminated by now..." + System.lineSeparator());
frame.getMainFrame().deactivateInfiGlass();
DebugToolbox.stopExecTimer();
}
};
worker.execute();
}});
The parsing of the values happens in an instance of Dataset
, using method addRow()
. The following piece of code shows the way the parsing error is handled
public double valueToIntensity(String val){
if(val.equalsIgnoreCase(""))
return missingVal;
try{
double d = Double.parseDouble(val);
switch(valType){
case RAW: break;
case LOG2: d = StrictMath.pow(2,d); break;
case LOGN: d = StrictMath.pow(StrictMath.E, d); break;
case LOG10: d = StrictMath.pow(10,d); break;
default: throw new RuntimeException("Unrecognized value type");
}
if(Double.isInfinite(d)){
StringBuilder msg = new StringBuilder("Double precision overflow occurred: 'd' is infinite!!");
msg.append(System.lineSeparator())
.append("chosen value scale is ").append(valType)
.append(System.lineSeparator())
.append("value = ").append(val);
logger.severe(msg.toString() + System.lineSeparator());
System.err.println("Data parsing error!!" +
"Please make sure that you have selected the correct scale...");
System.exit(FeverMainFrame.exitCodes.get(this.getClass()));
}
else
return d;
} catch (NumberFormatException e){
System.err.println("Data parsing error!!");
// THE FOLLOWING LINE IS WHERE DEADLOCK OCCURS
logger.severe("Expected: string representation of a numerical value, "
+ "Found: " + val + System.lineSeparator());
System.err.println("Please make sure the datafile does not include any strings "
+ "like 'N/A' or '-' for denoting missing values.");
System.exit(FeverMainFrame.exitCodes.get(this.getClass()));
}
// TODO: This should never happen!
throw new RuntimeException("Assertion failed during dataset parsing...");
}
If I remove the values that are causing the parsing error, without changing anything else, both the logging framework and the rest of application runs as expected.
I would really appreciate any insight as to what is going on in this particular case.