0

http リクエストのキューを最初から実装しようとすると問題が発生します。申し訳ありませんが、これは誰かにとって非常に単純な並行性の問題かもしれません。

基本的に、アプリケーションで一度に 1 つのリクエストのみを実行したいと考えています。追加のリクエストはキューに入れられ、後で実行されます。

FutureTask や Execution pool などの他の高度な機能については認識していますが、基本的な同時実行の問題を解決する方法に興味があるため、回答が必要です。以下は私のクラスがrequestQueueを維持することです

private Queue<HttpRequest> requestQueue;
private AsyncTask myAsyncTask=null;

public boolean send(HttpRequest hr){
   //if there isn't existing task, start a new one, otherwise just enqueue the request
   //COMMENT 1.
   if(myAsyncTask==null){
     requestQueue.offer(hr);
     myAsyncTask= new RequestTask();
     myAsyncTask.execute(null);
     return true;
   }
   else{
     //enqueue
     //COMMENT 2
     requestQueue.offer(hr);
   }

}

//nested class
RequestTask extends AsyncTask<boolean,void,void>{
      protected HttpResponse doInBackground(void... v){
           //send all request in the queue
           while(requestQueue.peek != null){
              HttpResquest r= requestQueue.poll
              //... leave out code about executing the request
           }
           return true;
      }

      protected void doPostExecute(boolean success){


           //COMMENT 3: if scheduler stop here just before myAsyncTask is set to null
           myAsyncTask=null;

      }
}

問題は、スレッド スケジューラがポイント 3 (myAsyncTask が null に設定される直前) でバックグラウンド スレッドを停止するかどうかです。

      //COMMENT 3: if scheduler stop here just before myAsyncTask is set to null
       myAsyncTask=null;

このとき、他のスレッドがたまたま COMMENT 1 のポイントに移動し、if ... else ... ブロックに入ります。myAsyncTask が null に設定されていないため、タスクは else ブロック (コメント 2) でキューに入れられますが、新しい asyncTask は作成されず、キューがスタックします!

   //COMMENT 1.
   if(myAsyncTask==null){
     requestQueue.offer(hr);
     myAsyncTask= new RequestTask;
     myAsyncTask.execute(null);
     return true;
   }
   else{
     //enqueue
     //COMMENT 2
     requestQueue.offer(hr);
   }

明確であることを願っています。キューの処理が停止する可能性があります。これを回避する方法を知りたいです。前もって感謝します

4

1 に答える 1

0

私が通常このようなものを実装する方法は、スレッドを拡張するクラスを作成することです。これにはキューオブジェクトが含まれ(任意のオブジェクトを使用)、ジョブを追加するためのメソッドが含まれます。同期を使用して、すべてのスレッドを安全に保ちます。通知と待機を使用して、ポーリングを回避できます。

これが役立つかもしれない例です...

    import java.util.*;

    public class JobProcessor extends Thread
    {
       private Queue queue = new LinkedList();

       public void addJob(Object job)
       {
           synchronized(queue)
           {
              queue.add(job);
              queue.notify(); // lests the thread know that an item is ready
           }
       }


       @Overide
       public void run()
       {
          while (true)
          {
              Object job = null;

              synchronized(queue) // ensures thread safety
              {
                 // waits until something is added to the queue.
                 try
                   while (queue.isEmpty()) queue.wait();
                 catch (InterruptedException e)
                   ; // the wait method can throw an exception you have to catch.
                 // but can ignore if you like.

                 job = queue.poll();
              }
              // at this point you have the job object and can process it!
              // with minimal time waiting on other threads.
              // be sure to check that job isn't null anyway!
              // in case you got an InterruptedException.

              ... processing code ...

              // job done loop back and wait for another job in the queue.
          }
       }
    }

このようなクラスをインスタンス化してスレッドを開始してから、オブジェクトを挿入してジョブを処理する必要があります。キューが空の場合、待機によりこのスレッドはスリープ状態になり(また、同期ロックが一時的に解放されます)、addJobメソッドでnotifyを実行すると、必要に応じてスレッドがウェイクアップします。同期は、1つのスレッドのみがキューにアクセスできるようにする方法です。それがどのように機能するかわからない場合は、javaSDKリファレンスで調べてください。

あなたのコードにはスレッドセーフコード(同期のもの)が含まれておらず、そこに問題があります。おそらく少し複雑すぎて、デバッグにも役立ちません。ただし、重要なことは、同期ブロックを追加する必要があることですが、それらをできるだけ短くするようにしてください。

于 2013-01-22T02:04:35.683 に答える