我因为以下棘手的问题而奋战了几天:
我有一个基于tomcat的Web应用程序,可以在任意时间向查询服务器发出请求。可能会同时触发两个或多个请求。
在接收端,我有一个处理这些请求的服务器,在通过spits重新调整结果列表后,在Tomcat上显示结果列表,显示jsp页面上的列表。
服务器只有一个对象的静态实例,实际上是通过数据进行搅拌(创建起来相当昂贵)。
现在,这就是我遇到瓶颈的问题:一方面,来自Tomcat的请求应该同步提供,以便Tomcat内部的管道可以工作并向用户显示合理的结果。 另一方面,如果它们是同步服务的,则处理方法(askQuery())对其他线程显示为锁定,而辅助请求返回为空。
我已经尝试过(几乎)所有可能的事情:在单独的线程中运行处理,同步方法等 - 至今无济于事。如果处理在单独的线程中运行,我无法产生结果并将列表同步返回给Tomcat。如果我加入()线程,该方法将显示为锁定状态。
以下是原始课程,用以说明我想要做的事情:
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()代码只是执行到最后而不等待线程完成。
对于我做错的任何帮助或建议表示赞赏。
答案 0 :(得分:0)
一个可能的原因是你在queryThread.isFinished
上有一个数据竞争:你从主线程读取它并从QueryThread线程写入它而没有同步。
使变量volatile可以解决该问题:volatile boolean isFinished = false;
。我不知道它是否能解决你的问题。
作为旁注:
askQuery
没有从使用线程中获得任何好处答案 1 :(得分:0)
好的偷看,感谢一百万的帮助。我已经弄明白了。
问题出现在推理器中,但在上游视图控制器中 - 方法:
public synchronized ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse res) throws Exception { .. }`
的
public class GeneListController implements Controller{
正在穿越电线并弄乱结果。
解决方案一直瞪着我的眼睛......
Tomcat日志显示每次都正确填充了SQL查询的ID列表(ID列表是所考虑的推理器的产品),但是生成的jsp页面返回为空。
将synchronized
添加到上述方法后,一切正常。
啊好吧......
第1课:阅读日志
第2课永远不要假设(即使有人告诉你问题是在线程中)