0

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.

4

2 回答 2

0

好的,谢谢你的帮助一百万。我已经想通了。

问题甚至没有出现在推理器中,而是出现在上游视图控制器中 - 方法:

public synchronized ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse res) throws Exception { .. }`

 public class GeneListController implements Controller{

正在交叉电线并弄乱结果。

解决方案一直让我眼前一亮……

Tomcat 日志显示 SQL 查询的 ID 列表(ID 列表是所考虑的推理器的产品)每次都正确填充,但是生成的 jsp 页面返回空。

添加synchronized到上述方法后,一切正常。

呃,好吧...

第 1 课:阅读日志

第 2 课永远不要假设任何事情(即使有人告诉你问题出在线程中)

于 2013-01-24T11:30:19.153 回答
0

一个可能的原因是您有数据竞争queryThread.isFinished:您从主线程读取它并从 QueryThread 线程写入它而没有同步。

使变量 volatile 可以解决该问题:volatile boolean isFinished = false;. 我不知道它是否会解决你的问题。

作为旁注:

  • 启动线程的想法是并行化作业。在您的情况下,您启动线程然后等待它完成,因此askQuery不会从使用线程中获得任何好处
  • 一个推论是活性问题:您在整个查询作业期间持有锁,阻止任何其他线程取得进展
于 2013-01-23T12:10:54.553 回答