マルチスレッドに関するある種のトリッキーな問題があります。私がしていることは、ExecutorService
接続を開いてそれらをに入れることを任務とするスレッドプール()を使用することLinkedBlockingQueue
です。
これまで私が使用したもの:
//run method in "getter threads"
public void run() {
try {
URL url = new URL(url_s); //url_s is given as a constructor argument
//if I am correct then url.openStream will wait until we have the content
InputStream stream = url.openStream();
Request req = new Request(); //a class with two variables:
req.html_stream = new InputSource(stream);
req.source = stream;
//this is a class variable (LinkedBlockingQueue<Request>)
blocking_queue.put(req);
} catch (Exception ex) {
logger.info("Getter thread died from an exeption",ex);
return;
}
}
InputSource
次に、これらのsとInputStream
sを取得して実行するコンシューマースレッド(java.lang.Thread)があります。
public void run() {
while(running) {
try {
logger.info("waiting for data to eat");
Request req = blocking_queue.take();
if(req.html_stream != null)
eat_data(req);
} catch (Exception ex) {
logger.error(ex);
return;
}
}
}
ここで、eat_dataは、InputSourceを受け取る外部ライブラリを呼び出します。ライブラリはシングルトンインスタンスを使用して処理を行うため、このステップを「getter」スレッドに入れることはできません。
このコードを少量のデータでテストしたところ、問題なく機能しましたが、数千のURLを提供したときに、実際の問題が発生し始めました。何が問題なのかを正確に特定するのは簡単ではありませんが、コンシューマスレッドが接続に到達する前に接続がタイムアウトし、デッドロックが発生することもあると思います。
url.openStream()からInputSourceに移動するのはとても簡単だったので、この方法で実装しましたが、これを機能させるには、データをローカルに保存する必要があることに気付きました。
url.openStream()から、LinkedBlockingQueue
(メモリ内のすべてのデータ)に格納できるオブジェクトに移動し、後でコンシューマースレッドが処理する時間があるときにInputSoruceに変換できるようにするにはどうすればよいですか?