2012-02-24 18 views
0

複数のスレッドに複数のWebページをロードする方法を見つけようとしました。 1つの終了時に新しいページが読み込まれます。また、ページがダウンロードされた後にロードされたコンテンツ用の別の後処理スレッドが存在し、プロセス全体が連鎖するようにする必要があります。新しいタスクが開始できるときに通知するコールバック付きのJavaタスクキュー、スレッドプール、およびスレッド

私はそれをしたいのですがどのように

  • タスクキューは、スレッドプールがページをロードするタスクキュー内のページをダウンロードするスレッドの一定数が(とりました
  • をダウンロードする必要があるページを保持していますページのダウンロードが完了すると、キューから新しいタスクが代わりに
  • 開始することができるように、スレッドはこれを通知しなければならない
  • ) スレッドの数は、CPUコアの数よりもはるかに高くなることができるようにいくつかの時間

    ページのダウンロードが完了したら、後処理のために別のタスクキューにコンテンツを転送する必要があります

  • 他のスレッドプールにはCPUコア数と同じスレッド数があります後処理の場合)、このスレッドプールはダウンロードしたページに対して後処理を行います。

  • ページの後処理が完了すると、すべてのページがダウンロードされている場合は、キュー内の他のページは

  • 事後処理できるように、スレッドはそれを通知しなければならないが(キューが空です)、

      for (int j = 0; j < threads.length; j++) { 
          threads[j].start(); 
         } 
    
         for (int j = 0; j < threads.length; j++) { 
          threads[j].join(); 
         } 
    
    :最初のスレッドプールは、私のようなものを持っている

(全てのページがダウンロードされ、後処理されています)の両方のタスクキューが空の場合、他のスレッドプールをシャットダウンすることができ、シャットダウンすることができ

しかし、このようにしてロードするすべてのページは別々のスレッドに同時にあり、スレッドの数を制限したい。もっと重要なのは、スレッドを再利用して、1つのタスクが終了したときにスレッドが次のタスクを実行したいということです。私はwhileループでこれを行うことができますが、これは私が避けようとしているものです。キューがより多くのタスクを持っているかどうか、そしてスレッドが空いているかどうかをwhileループがチェックすることは望ましくありません。何らかのコールバックを使用することができるので、スレッドは完了したプールに戻るように指示し、データを返します。 私はまた、ダウンロードタスクが〜のコンテンツをデータ構造に格納し、それを後処理タスクキューに追加することも望みます。

私がこれまでに見つかった最良のリソースは次のとおりです。 Thread pools Callback

しかし、それもそれを私が望む方法を作成することが可能であるかどうかはわかりません。私は関数ポインタについて考えるのをやめました。

答えて

3

低レベルのスレッドメソッドを使用しないでください。 downloadExecutorスレッドプールを持ち、DownloadTaskインスタンス(RunnableまたはCallableを実装)をこのプールに送信します。

DownloadTaskのコードの終わりに、第二postProcessExecutorスレッドプールに(再びRunnable又はCallableを実装する実装)PostProcessPageTaskインスタンスを提出します。

すべてのタスクが終了すると1つまたは2つのCountDownLatchインスタンスを使用して、スレッドプールをシャットダウンする必要があることを知るためにメインスレッドがこの(またはこれらの)ラッチを待機します。

詳細は、http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.htmlおよびdocs.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.htmlを参照してください。

+1

2つのプールを使用している点はありますか? 1つのプールで1つのタスククラスでダウンロードして処理するだけではいかがですか。ダウンロードしたデータを同じプロセッサコアを使用している別のプールにキューイングしても、私には利点はありません。 –

+0

私はそのJBを見て、後であなたに戻ってきます。私は、PostProcessPageTaskを2番目のエグゼキュータに提出するDownloadTaskを持っていると思っています。 – user979899

+0

@Martin: 私はすべてをシリアルで行い、全くパラレルではないかもしれませんが、もっと速くしようとしていました。ページからコンテンツをダウンロードするのは転送速度に大きく依存します(CPUに余分な負荷がかからない限り)ので、同時に多数のページをダウンロードできますが、コンテンツの後処理はCPUの負荷だけに依存します。したがって、一度に100ページからコンテンツをダウンロードするとしたら、後処理を行っているスレッドは約100個になりますが、効率的ではありません。 – user979899

1

グアバのListenableFuturesを使用できます。

最初にListenableExecutorServiceにダウンロードタスクを提出し、結果のフューチャーをポストプロセッサFutures.transformで変換する必要があります。

ListenableExecutorService dlPool = MoreExecutors.listeningDecorator(firstPool); 
ListenableExecutorService procPool = MoreExecutors.listeningDecorator(secondPool); 

List<ListenableFuture<Result>> results = new ArrayList<...>(); 
for (String url : urls) { 
    // download task 
    ListenableFuture<String> html = dlPool.submit(...); 
    // post process 
    ListenableFuture<Result> result = Futures.transform(html, 
    new Function<String, Result>() { 
     ... // post process 
    }, procPool); 
    results.add(result); 
} 

// blocks until all results are processed 
List<Result> processed = Futures.allAsList(results).get(); 

firstPool.shutdownNow(); 
secondPool.shutdownNow(); 
-1

このタイプの一般インフラストラクチャを手作業でコード化しないでください。

素敵java.util.concurrentパッケージでJava 5と上記船

それはあなたがマルチスレッド・アプリケーションを作成する際に向ける最初のものになるはずです。

Threadpools(RunnableまたはCallableオブジェクトを実行する)のような一般的なツールがたくさんあり、あなたのために多くの犬の仕事をします。

インターネット上で多くの無料リソースがあります。書籍を好む場合は、Brian Goetzの「Java Concurrency in Practice」が広く利用されています。

関連する問題