私は次のトリッキーな問題で数日間戦っています:
任意の時間にクエリ サーバーにリクエストを送信する tomcat ベースの Web アプリケーションがあります。2 つ以上のリクエストが同時に発生する可能性があります。
受信側には、これらのリクエストを処理するサーバーがあり、それらを検討した後、Tomcat に結果のリストを吐き出し、jsp ページにリストを表示します。
サーバーには、実際にデータをかき回すオブジェクトの静的インスタンスが 1 つしかありません (作成にはかなりのコストがかかります)。
ここでボトルネックが発生します。一方で、Tomcat からのリクエストは同期的に処理され、Tomcat 内のパイプラインが機能し、適切な結果がユーザーに表示されるようにする必要があります。一方、それらが同期的に処理される場合、処理メソッド (askQuery()) は他のスレッドに対してロックされているように見え、2 番目の要求は空を返します。
別のスレッドで処理を実行する、メソッドを同期するなど、(ほぼ)すべての可能なことを試しましたが、まだ役に立ちません。処理が別のスレッドで実行される場合、結果を生成してリストを同期的に Tomcat に返すことができません。スレッドに join() すると、メソッドがロックされているように見えます。
私がやりたいことのアイデアを説明するための元のクラスは次のとおりです。
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;
}
}
}
問題は、askQuery() がまだロックされ、後続のすべてのクエリが空の結果を返すことです。
askQuery() から Thread.sleep() を削除すると、非同期で動作しますが、結果はまったく返されません.askQuery()コードは、スレッドが終了するのを待たずに最後まで実行されます。
私が間違っていることについての助けやアドバイスをいただければ幸いです。