I have been fighting for a couple of days with the following tricky problem:
I have a tomcat-based web application that fires request to the query server at arbitrary time. Potentially two or more requests can be fired at the same time.
On the receiving side I have a server that processes these requests and after mulling them over spits the list of results back at Tomcat, that displays the list on the jsp page.
The server has only one static instance of the object that actually churns through the data (being rather expensive to create).
Now that is where I have a bottleneck: on the one hand, the requests from Tomcat should be served synchronously so that the pipeline inside Tomcat could work and display sensible results to the user. On the other hand, if they are served synchronously, the processing method (askQuery()) appears locked for other threads and secondary requests return empty.
I have tried (nearly) every possible thing: running processing in a separate thread, synchronize the method, etc - to no avail as yet. If the processing runs in a separate thread I can not yield the results and return the list synchronously to Tomcat. If I join() the thread, the method appears locked.
Here is the original class to illustrate the idea of what I want to do:
package...
imports...
public class DLQueryEngineBrain extends ADLQueryEngine{
protected static Brain brain;
protected static boolean isFree = true;
protected AOwlResultParser orp;
private QueryThread queryThread;
public DLQueryEngineBrain(String ontologyURL, ThirdPartyBeanManager tpbm) {
super(ontologyURL, tpbm);
try {
DLQueryEngineBrain.brain = new Brain("http://purl.obolibrary.org/obo/", "http://purl.obolibrary.org/obo/fbbt.owl", 32);
LOG.debug("BRAIN': " + brain + " this " + this);
brain.learn(ontologyURL);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.orp = new OwlResultParserClass(this.ontology);
}
// This is the method I want to run asynchronously, but I want it to return results //in-line of the calling method, eg.
//results = queryEngineBrain.askQuery("sublcass of some X"), and use the results in the //subsequent code...
public synchronized Set<OntBean> askQuery(OntQueryQueue oqq) {
LOG.debug("Input: " + oqq.toString());
Set<OntBean> results = new TreeSet<OntBean>();
QueryThread queryThread = new QueryThread(oqq, (OwlResultParserClass)this.orp);
queryThread.start();
while (!queryThread.isFinished){
try {
Thread.sleep(10);
LOG.debug("Main Thread sleeps...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
LOG.debug("Output: " + queryThread.results.size());
return queryThread.results;
}
class QueryThread extends Thread {
int number;
private Set<OntBean> results = new TreeSet<OntBean>();
private OntQueryQueue oqq;
private OwlResultParserClass orp;
boolean isFinished = false;
//Just save the number to display on the console
public QueryThread(OntQueryQueue oqq, OwlResultParserClass orp) {
this.number = DLQueryEngineBrain.numThreads++;
this.oqq = oqq;
this.orp = orp;
}
public void run () {
while(!this.isFinished) {
LOG.debug("DLQueryEngineBrain.isFree: " + DLQueryEngineBrain.isFree);
if (DLQueryEngineBrain.isFree){
this.runQuery();
this.isFinished = true;
}
else {
LOG.debug("Query thread sleeps while brain is busy...");
try {
Thread.sleep(getRandInt());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void runQuery() {
DLQueryEngineBrain.isFree = false;
List<String> queries = this.oqq.getQueries();
LOG.debug("BRAIN : " + DLQueryEngineBrain.brain + " this " + this);
for (String currExpr: queries){
LOG.debug("currExpr: " + currExpr);
List<String> subClasses = null;
try {
subClasses = DLQueryEngineBrain.brain.getSubClasses(currExpr, true);
} catch (ClassExpressionException e) {
e.printStackTrace();
}
LOG.debug("Found: " + subClasses.size());
//Iterates over the list and print the result.
for (String subClass : subClasses) {
this.results.add(orp.getOntBeanForId(subClass));
}
}
DLQueryEngineBrain.isFree = true;
}
private int getRandInt(){
double d = Math.random();
int i = Math.round((float)d*100);
return i;
}
}
}
The problem is the askQuery() still locks up and all subsequent queries return empty results.
Removing the Thread.sleep() from the askQuery() results in it working asynchronously but no results returned whatsoever- the askQuery() code just executes to the end without waiting for the thread to finish.
Any help or advice on what I am doing wrong is appreciated.