如果我遇到以下情况:
ObserverA,ObserverB,ObserverC都继承自AbstractObserver。
我创建了一个观察者列表:
List<AbstractObserver> list = new ArrayList<AbstractObserver>();
list.add(new ObserverA());
list.add(new ObserverB());
list.add(new ObserverC());
使用以下方法的某种处理程序在“MAIN”线程中运行:
public void eat(Food item) {
for(AbstractObserver o : list) {
o.eatFood(item);
}
}
public void drink(Coffee cup) {
for(AbstractObserver o : list) {
o.drinkCoffee(cup);
}
}
我如何设计一个系统,我可以在不同的线程中运行每个eatFood和drinkCoffee方法的观察者?具体来说,当“MAIN”线程收到事件(饮料或吃方法被调用)时,如何在ObserverA,ObserverB和ObserverC中运行自己的线程中的eatFood或drinkCoffee方法?
我想为每个AbstractObserver子类实例设置不同的线程,因为目前我正在按顺序通知每个观察者,这可能会导致延迟。
答案 0 :(得分:3)
在这里做一些简化的假设,你不关心在吃/喝结束时得到通知,你也可以使用执行器框架将工作扔到队列中:
// declare the work queue
private final Executor workQueue = Executors.newCachedThreadPool();
// when you want to eat, schedule a bunch of 'eating' jobs
public void eat(final Food item){
for (final AbstractObserver o: list) {
workQueue.execute(new Runnable() {
@Override
public void run() {
o.eatFood(item); // runs in background thread
}
});
}
}
退出程序时,必须关闭执行程序:
workQueue.shutdown();
答案 1 :(得分:2)
我不是这方面的专家,但也许你可以使用Producer-consumer设置。在这里,生产者,即观察到的实体,可以在其自己的线程中的队列上添加通知,消费者(此处的观察者)将从同一队列获取,但是在其自己的线程上。
答案 2 :(得分:2)
详细说明Hovercraft的答案,观察者的基本实现可能如下所示:
class ObserverA implements Runnable {
private final BlockingQueue<Food> queue = new ArrayBlockingQueue<> ();
public void eatFood(Food f) {
queue.add(f);
}
public void run() {
try {
while (true) {
Food f = queue.take(); //blocks until some food is on the queue
//do what you have to do with that food
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
//and exit
}
}
}
因此,调用eatFood
的代码将立即从该方法返回,而不会阻止您的主线程。
你显然需要直接向观察者分配一个线程:new Thread(observerA).start();
或者通过ExecutorService,这可能更容易和更可取。
或者,您可以在“观察”对象级别创建线程:
private static final ExecutorService fireObservers = Executors.newFixedThreadPool(10);
public void eat(Food food) {
for (AbstractObserver o : observers) {
//(i) if an observer gets stuck, the others can still make progress
//(ii) if an observer throws an exception, a new thread will be created
Future<?> f = fireObservers.submit(() -> o.dataChanged(food));
fireObservers.submit(new Callable<Void>() {
@Override public Void call() throws Exception {
try {
f.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.warn("Slow observer {} has not processed food {} in one second", o, food);
} catch (ExecutionException e) {
logger.error("Observer " + o + " has thrown exception on food " + food, e.getCause());
}
return null;
}
});
}
}
(我主要是从here复制粘贴 - 你可能需要根据自己的需要调整它。)