假设我们想让Flux管道处理来自多个线程的所有消息。我们考虑下面的代码:
@Test
public void testFluxCreate() throws InterruptedException {
EmitterProcessor<String> processor = EmitterProcessor.create();
CountDownLatch latch = new CountDownLatch(1);
AtomicLong counter = new AtomicLong();
AtomicLong batch = new AtomicLong();
Flux<List<String>> flux = processor
.doOnSubscribe(ss -> System.out.println(nm() + " : subscribing to + ss))
.onBackpressureError()
.buffer(7)
.publishOn(Schedulers.immediate())
.doOnNext(it -> {
counter.addAndGet(it.size());
System.out.println(batch.incrementAndGet() + " : " + nm() + "Batch: " + it.size());
})
;
CompletableFuture<Void> producer = CompletableFuture.runAsync(() -> {
IntStream.range(1, 1001).forEach(it -> {
//sleep();
processor.onNext("Message-" + it);
});
});
CompletableFuture<Void> producer2 = CompletableFuture.runAsync(() -> {
IntStream.range(1, 1001).forEach(it -> {
//sleep();
processor.onNext("Message2-" + it);
});
});
CompletableFuture<Void> future = CompletableFuture.allOf(producer, producer2).thenAccept(it -> processor.onComplete());
flux.doOnComplete(latch::countDown).subscribe();
future.join();
latch.await();
System.out.println("Total: " + counter);
}
计数器告诉我们,每次执行此代码时,处理的实际消息数都是不同的。 这个实现有什么问题? 我们如何确保在程序结束之前处理所有消息?
答案 0 :(得分:1)
这个实现有什么问题?
当我运行代码时,我在开始后的日志中得到以下内容:
BooleanView.xib
我不熟悉class BooleanView: UIView {
@IBOutlet var contentView: UIView!
@IBOutlet weak var leftButton: UIButton!
@IBOutlet weak var rightButton: UIButton!
//MARK: Initialization
override init(frame: CGRect) {
super.init(frame: frame)
// Load the nib named 'CardView' into memory, finding it in the main bundle.
Bundle.main.loadNibNamed("BooleanView", owner: self, options: nil)
self.frame = contentView.frame
addSubview(contentView)
// Style the custom view
contentView.backgroundColor = UIColor.clear
leftButton.layer.cornerRadius = (leftButton.frame.height / 2)
rightButton.layer.cornerRadius = (rightButton.frame.height / 2)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
@IBAction func pressedButton(_ sender: UIButton) {
if sender.backgroundColor == Constants.BOOL_BUTTON.enabled {
return
}
sender.backgroundColor = Constants.BOOL_BUTTON.enabled
sender.titleLabel?.font = UIFont(name: Constants.FONTS.bold, size: (sender.titleLabel?.font.pointSize)!)
if sender.tag == 0 {
self.rightButton.backgroundColor = Constants.BOOL_BUTTON.disabled
self.rightButton.titleLabel?.font = UIFont(name: Constants.FONTS.regular, size: (self.rightButton.titleLabel?.font.pointSize)!)
} else {
self.leftButton.backgroundColor = Constants.BOOL_BUTTON.disabled
self.leftButton.titleLabel?.font = UIFont(name: Constants.FONTS.regular, size: (self.leftButton.titleLabel?.font.pointSize)!)
}
}
}
,但似乎18:39:12.590 [ForkJoinPool.commonPool-worker-1] DEBUG reactor.core.publisher.Operators - Duplicate Subscription has been detected
java.lang.IllegalStateException: Spec. Rule 2.12 - Subscriber.onSubscribe MUST NOT be called more than once (based on object equality)
at reactor.core.Exceptions.duplicateOnSubscribeException(Exceptions.java:162)
at reactor.core.publisher.Operators.reportSubscriptionSet(Operators.java:502)
at reactor.core.publisher.Operators.setOnce(Operators.java:607)
at reactor.core.publisher.EmitterProcessor.onNext(EmitterProcessor.java:245)
at de.schauder.reactivethreads.demo.StackoverflowQuicky.lambda$null$2(StackoverflowQuicky.java:54)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:557)
at de.schauder.reactivethreads.demo.StackoverflowQuicky.lambda$main$3(StackoverflowQuicky.java:52)
不是线程安全的,我强烈怀疑这是导致丢失事件的原因。
我们如何确保在程序结束前处理所有消息?
我会使用两个单独的EmitterProcessor
和onNext
。另外我认为你不需要倒计时锁。
Producers
请注意我的评论:
当订阅者无法足够快地处理所有事件时, merge
会导致public static void main(String[] args) {
AtomicLong counter = new AtomicLong();
AtomicLong batch = new AtomicLong();
EmitterProcessor<String> processor1 = EmitterProcessor.create();
EmitterProcessor<String> processor2 = EmitterProcessor.create();
Thread thread1 = constructThread(processor1);
Thread thread2 = constructThread(processor2);
Flux<List<String>> flux = processor1.mergeWith(processor2)
.buffer(7)
.onBackpressureError()
.publishOn(Schedulers.immediate())
.doOnNext(it -> {
counter.addAndGet(it.size());
System.out.println(batch.incrementAndGet() + " : Batch: " + it.size());
}).doOnComplete(() -> {
System.out.println("Total count: " + counter.get());
});
thread1.start();
thread2.start();
flux.blockLast();
}
private static Thread constructThread(EmitterProcessor<String> processor) {
return new Thread(() -> {
IntStream.range(1, 1001).forEach(it -> {
processor.onNext("Message2-" + it);
});
processor.onComplete();
});
}
发出错误,因此这可以解释不匹配,但您会看到异常。