我已经在我的应用程序中实现了发布和订阅模式,但是当我在任何一个订阅者中调用Thread.sleep()
方法或我的任何一个订阅者抛出异常时,所有其他订阅者和发布者都会受到此影响,因此如何防止这是发生的。
我已经创建了一个有关上述问题的小演示
发布者代码
import java.util.Random;
public class Publisher extends Thread {
Broker broker = Broker.getInstance();
Random random = new Random();
@Override
public void run() {
while (true) {
System.out.println("Published " + new Timestamp(System.currentTimeMillis()));
broker.updateSubscribers(Integer.toString(random.nextInt(250)));
}
}
}
用户界面
public interface Subscriber {
public void onUpdate(String message);
}
MessageSubscriber代码
import java.util.logging.Level;
import java.util.logging.Logger;
public class MessageSubscriber extends Thread implements Subscriber {
Broker broker = Broker.getInstance();
@Override
public void run() {
System.out.println("MessageSubscriber started...");
broker.subscribe(this);
}
@Override
public void onUpdate(String message) {
try {
System.out.println(message);
sleep(1000); // called sleep affects the publisher too
} catch (InterruptedException ex) {
Logger.getLogger(MessageSubscriber.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
如您所见,我在MessageSubscriber中调用了sleep方法,这也影响了发布服务器并使它在该时间内也保持睡眠状态
编辑添加的经纪人代码
import java.util.ArrayList;
import java.util.List;
/**
*
* @author hemants
*/
public class Broker {
List<Subscriber> subscribersList = new ArrayList<>();
private Broker() {
}
public static Broker getInstance() {
return BrokerHolder.INSTANCE;
}
private static class BrokerHolder {
private static final Broker INSTANCE = new Broker();
}
public void subscribe(Subscriber s) {
subscribersList.add(s);
}
public void unsubscribe(Subscriber s) {
subscribersList.remove(s);
}
public void updateSubscribers(String message) {
subscribersList.stream().forEach(subscriber -> subscriber.onUpdate(message));
}
}
运行上述代码的主类
public class PubSubPattern {
public static void main(String[] args) {
Publisher publisher = new Publisher();
publisher.start();
MessageSubscriber messageSubscriber = new MessageSubscriber();
messageSubscriber.start();
}
}
好吧,我已经编辑了MessageSubscribe代码,如下所示,它的工作符合我的预期
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author hemants
*/
public class MessageSubscriber extends Thread implements Subscriber {
Broker broker = Broker.getInstance();
@Override
public void run() {
System.out.println("MessageSubscriber started...");
while (true) {
try {
broker.subscribe(this);
System.out.println("subscribed ");
sleep(1000);
broker.unsubscribe(this);
System.out.println("un subscribed");
sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(MessageSubscriber.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
@Override
public void onUpdate(String message) {
System.out.println(message);
}
}
你怎么说?
答案 0 :(得分:1)
所以您执行这样的事情
subscribersList.stream().forEach(subscriber -> subscriber.onUpdate(message));
在onUpdate
期间,您sleep
因此有效
subscribersList.stream().forEach(subscriber -> Thread.sleep());
或更详细
for(Subscriber sub:subscribers){
Thread.sleep(xxx);
}
难怪它会“影响”其他侦听器,因为此处阻止了呼叫者。调用者线程在每个元素上睡眠。
要么使用线程池并提交更新任务,要么使用subscribersList.parallelStream()
我希望这只是出于教育目的。
答案 1 :(得分:0)
您正在同一线程中更新订户,这就是为什么它将影响其他订户的原因。并阻止发布者。
创建新线程以更新代理,就可以了。
答案 2 :(得分:0)
这是一个快速的解决方案。我更新了MessageSubscriber
,将接口Subscriber
的用法保留在Broker
中:
public class MessageSubscriber extends Thread implements Subscriber {
Broker broker = Broker.getInstance();
@Override
public void run() {
System.out.println("MessageSubscriber started...");
synchronized (broker) {
broker.subscribe(this);
}
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// TODO OP has to decide how to handle this
// for example
synchronized (broker) {
broker.unsubscribe(this);
}
}
}
@Override
public void onUpdate(String message) {
try {
synchronized (this) {
notify();
}
System.out.println(message);
sleep(1000); // called sleep affects the publisher too
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
Logger.getLogger(MessageSubscriber.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
我不确定InterruptedException
中run()
的处理方式,因为必须输入boker
的锁才能进入同步块。因此,线程可能会等待此锁定,而不是有效地中断自身。