0

私は次のトリッキーな問題で数日間戦っています:

任意の時間にクエリ サーバーにリクエストを送信する 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()コードは、スレッドが終了するのを待たずに最後まで実行されます。

私が間違っていることについての助けやアドバイスをいただければ幸いです。

4

2 に答える 2

0

考えられる理由の 1 つは、でデータ競合が発生していることですqueryThread.isFinished。メイン スレッドから読み取り、同期せずに QueryThread スレッドから書き込みます。

変数を volatile にすると、その問題が解決します: volatile boolean isFinished = false;. それがあなたの問題を解決するかどうかはわかりません。

サイドコメントとして:

  • スレッドを開始するという考えは、ジョブを並列化することです。あなたの場合、スレッドを開始してから終了するまで待つため、スレッドaskQueryを使用してもメリットはありません
  • 結果は活性の問題です。クエリジョブ全体でロックを保持し、他のスレッドが進行するのを防ぎます
于 2013-01-23T12:10:54.553 に答える
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 に答える