[英]Concurrent Observer Pattern
如果我遇到以下情況:
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子類實例設置不同的線程,因為目前我正在按順序通知每個觀察者,這可能會導致延遲。
在這里做一些簡化的假設,你不關心在吃/喝結束時得到通知,你也可以使用執行器框架將工作扔到隊列上:
// 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();
我不是這方面的專家,但也許你可以使用Producer-consumer設置。 在這里,生產者,即觀察到的實體,可以在其自己的線程中的隊列上添加通知,消費者(此處的觀察者)將從同一隊列獲取,但是在其自己的線程上。
要詳細說明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;
}
});
}
}
(我大部分都是從這里粘貼的 - 你可能需要根據自己的需要調整它)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.