簡體   English   中英

並發觀察者模式

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM