我想使用Java实现各种发布者/订阅者模式,并且目前用完了想法。
有1个发布者和N个订阅者,发布者发布对象,然后每个订阅者需要一次处理每个对象,并且只按正确的顺序处理一次。发布者和每个订阅者都在自己的主题中运行。
在我最初的实现中,每个订阅者都有自己的阻塞队列,发布者将对象放入每个订阅者的队列中。这可以正常工作,但如果任何订户的队列已满,将阻止发布者。这导致性能下降,因为每个订户在处理对象时花费不同的时间。
然后在另一个实现中,发布者将对象保存在自己的队列中。与对象一起,AtomicInteger计数器与其关联,其中包含订户数。然后,每个订户查看队列并减少计数器,并在计数器达到零时将其从队列中删除。
通过这种方式,发布者可以免于阻止,但现在订阅者需要等待彼此处理对象,从队列中删除对象,然后才能查看下一个对象。
有没有更好的方法呢?我认为这应该是一种非常常见的模式。
答案 0 :(得分:0)
你的"很多队列"实施是要走的路。我不认为您需要关注阻止生产者的一个完整队列,因为完成的总时间不会受到影响。假设你有三个消费者,两个消费者以每秒1个的速度消费,第三个消费者以每五秒1个的速度消费,同时生产者以每两秒一个的速度消费。最终第三个队列将填满,因此生产者将阻止它,并且还将停止将项目放在第一个和第二个队列中。有很多方法可以解决这个问题,但他们并没有改变第三个消费者总是成为瓶颈的事实。如果您正在生产/消费100件商品,那么由于第三个消费者(5件次100件商品),这将至少需要500秒,即使第一个和第二个消费者在200秒后完成也是如此(因为你已经做了一些聪明的事情,允许生产者在第三个队列满了之后继续填充他们的队列)或者他们在500秒后完成(因为生产者在第三个队列上被阻止)。
答案 1 :(得分:0)
肯定
每个订阅者都有自己的阻塞队列,发布者将对象放入每个订阅者的队列中。
这是要走的路。 您可以使用线程方法将其放入队列中...因此,如果一个队列已满,则发布者不会等待..
例如。
s1 s2 s3是订阅者,addToQueue
是每个订阅者中添加到相应队列的方法。
addQueue
方法等待队列非空。所以拨打addQueue
将是阻止呼叫ideally synchronised code
...
然后在发布商中,您可以执行与以下代码类似的操作
注意:代码可能不是处于工作状态,但是应该给你一些想法。
List<subscriber> slist;// Assume its initialised
public void publish(final String message){
for (final subscriber s: slist){
Thread t=new Thread(new Runnable(){
public void run(){
s.addToQueue(message);
}
});
t.start();
}
}
答案 2 :(得分:0)
有1个发布者和N个订阅者,发布者发布对象,然后每个订阅者需要一次处理每个对象,并且只按正确的顺序处理一次。发布者和每个订阅者都在自己的主题中运行。
我会改变这种架构。我最初考虑每个用户的队列,但我不喜欢这种机制。例如,如果第一个订阅者需要更长的时间来运行,那么所有作业将最终进入该队列,并且您将只执行1个工作线程。
由于你必须按顺序运行订阅者,我会有一个线程池,它通过所有订阅者运行每条消息。对订户的呼叫需要是可重入的,这可能是不可能的。
所以你将拥有一个包含10个线程的池(比方说),每个线程都从发布者的队列中出列,并执行以下操作:
public void run() {
while (!shutdown && !Thread.currentThread().isInterrupted()) {
Article article = publisherQueue.take();
for (Subscriber subscriber : subscriberList) {
subscriber.process(article);
}
}
}