Java 9でSubscriber
とPublisher
がどのように機能するかを理解しようとしています。
ここで1つのsubscriber
を作成し、アイテムの公開にSubmissionPublisher
を使用しています。
100個の文字列をsubscriber
に公開しようとしています。 Client
プログラムをsleep
にしないと(MyReactiveApp
のコメント付きコードを参照)、すべてのアイテムが公開されているとは限りません。
ここで処理されるすべての文字列を待機しないのはなぜですか。
strs.stream().forEach(i -> publisher.submit(i)); // what happens here?
上記のコードをに置き換えると、すべての文字列がコンソールに出力されます
strs.stream().forEach(System.out::println);
SubmissionPublisher
を使用して公開するクライアントプログラム。
import Java.util.List;
import Java.util.concurrent.SubmissionPublisher;
import Java.util.function.Supplier;
import Java.util.stream.Collectors;
import Java.util.stream.Stream;
public class MyReactiveApp {
public static void main(String args[]) throws InterruptedException {
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
MySubscriber subs = new MySubscriber();
publisher.subscribe(subs);
List<String> strs = getStrs();
System.out.println("Publishing Items to Subscriber");
strs.stream().forEach(i -> publisher.submit(i));
/*while (strs.size() != subs.getCounter()) {
Thread.sleep(10);
}*/
//publisher.close();
System.out.println("Exiting the app");
}
private static List<String> getStrs(){
return Stream.generate(new Supplier<String>() {
int i =1;
@Override
public String get() {
return "name "+ (i++);
}
}).limit(100).collect(Collectors.toList());
}
}
サブスクライバー
import Java.util.concurrent.Flow.Subscription;
public class MySubscriber implements Java.util.concurrent.Flow.Subscriber<String>{
private Subscription subscription;
private int counter = 0;
@Override
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
subscription.request(100);
}
@Override
public void onNext(String item) {
System.out.println(this.getClass().getSimpleName()+" item "+item);
//subscription.request(1);
counter++;
}
@Override
public void onError(Throwable throwable) {
System.out.println(this.getClass().getName()+ " an error occured "+throwable);
}
@Override
public void onComplete() {
System.out.println("activity completed");
}
public int getCounter() {
return counter;
}
}
出力:
Publishing Items to Subscriber
MySubscriber item name 1
MySubscriber item name 2
MySubscriber item name 3
MySubscriber item name 4
MySubscriber item name 5
Exiting the app
MySubscriber item name 6
MySubscriber item name 7
MySubscriber item name 8
MySubscriber item name 9
MySubscriber item name 10
MySubscriber item name 11
MySubscriber item name 12
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
ForkJoinPool.commonPool()を使用して、サブスクライバーへの非同期配信用に新しいSubmissionPublisherを作成します
だから実際には
strs.stream().forEach(i -> publisher.submit(i));
すべての送信をキューに入れ、別のスレッドで非同期に配信します。しかし、その後、アプリケーションは終了します。これは、ワーカースレッドの進行状況とは無関係です。これは、ワーカースレッドがすでに配信した要素の数に関係なく、アプリケーションが終了することを意味します。
これは、実行ごとに異なる可能性があります。最悪の場合、最初のアイテムが配信される前にアプリケーションが終了する可能性があります。
スレッド
MyReactiveAppのメインメソッドとMySubscriberのonNextでの配信が異なるスレッドで行われることを確認する場合は、対応するスレッドの名前を出力できます。 MyReactiveAppのメイン:
System.out.println(Thread.currentThread().getName())
スレッド名としてmain
を出力します。
MySubscriberのonNextメソッドは、たとえばForkJoinPool.commonPool-worker-1
のようなものを出力します。
ユーザースレッドとデーモンスレッド
実行中のスレッドがまだあるのに、なぜアプリケーションが終了するのですか?
Javaには2種類のスレッドがあります。
Javaプログラムは、デーモンスレッドがまだ実行されている場合でも、ユーザースレッドが実行されなくなると終了します。
メインスレッドはユーザースレッドです。 SubmissionPublisherは、ここでForkJoinPool.commonPool()のワーカースレッドを使用します。これらはデーモンスレッドです。
すべてのワーカースレッドは、Thread.isDaemon()をtrueに設定して初期化されます。
https://docs.Oracle.com/javase/9/docs/api/Java/util/concurrent/ForkJoinPool.html