Шаблон разработки наблюдателя

Вы попробовали

(setq  tab-width  4)
5
задан Saro Taşciyan 10 February 2014 в 00:54
поделиться

7 ответов

Классические шаблоны проектирования не предполагают параллелизма и многопоточности. Вам нужно будет создать N потоков для N наблюдателей. Однако будьте осторожны, поскольку их взаимодействие с , это должно быть выполнено с использованием потоковой безопасности.

10
ответ дан 18 December 2019 в 05:21
поделиться

Вы можете использовать метод java.utils.concurrent.Executors.newFixedThreadPool (int nThreads), а затем вызвать метод invokeAll (также можно использовать метод с таймаутом, чтобы избежать бесконечная петля).

Вы бы изменили свой цикл, добавив класс Callable, который принимает «наблюдатель» и «this», а затем вызовите метод обновления в методе «call».

Взгляните на этот пакет, чтобы узнать больше. info .

Это быстрая и грязная реализация того, о чем я говорил:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Main
{
    private Main()
    {
    }

    public static void main(final String[] argv)
    {
        final Watched       watched;
        final List<Watcher> watchers;

        watched = new Watched();
        watchers = makeWatchers(watched, 10);
        watched.notifyWatchers(9);
    }

    private static List<Watcher> makeWatchers(final Watched watched,
                                              final int     count)
    {
        final List<Watcher> watchers;

        watchers = new ArrayList<Watcher>(count);

        for(int i = 0; i < count; i++)
        {
            final Watcher watcher;

            watcher = new Watcher(i + 1);
            watched.addWatcher(watcher);
            watchers.add(watcher);
        }

        return (watchers);
    }
}

class Watched
{
    private final List<Watcher> watchers;

    {
        watchers = new ArrayList<Watcher>();
    }

    public void addWatcher(final Watcher watcher)
    {
        watchers.add(watcher);
    }

    public void notifyWatchers(final int seconds)
    {
        final List<Watcher>         currentWatchers;
        final List<WatcherCallable> callables;
        final ExecutorService       service;

        currentWatchers = new CopyOnWriteArrayList<Watcher>(watchers);
        callables       = new ArrayList<WatcherCallable>(currentWatchers.size());

        for(final Watcher watcher : currentWatchers)
        {
            final WatcherCallable callable;

            callable = new WatcherCallable(watcher);
            callables.add(callable);
        }

        service = Executors.newFixedThreadPool(callables.size());

        try
        {
            final boolean value;

            service.invokeAll(callables, seconds, TimeUnit.SECONDS);
            value = service.awaitTermination(seconds, TimeUnit.SECONDS);
            System.out.println("done: " + value);
        }
        catch (InterruptedException ex)
        {
        }

        service.shutdown();
        System.out.println("leaving");
    }

    private class WatcherCallable
        implements Callable<Void>
    {
        private final Watcher watcher;

        WatcherCallable(final Watcher w)
        {
            watcher = w;
        }

        public Void call()
        {
            watcher.update(Watched.this);
            return (null);
        }
    }
}

class Watcher
{
    private final int value;

    Watcher(final int val)
    {
        value = val;
    }

    public void update(final Watched watched)
    {
        try
        {
            Thread.sleep(value * 1000);
        }
        catch (InterruptedException ex)
        {
            System.out.println(value + "interupted");
        }

        System.out.println(value + " done");
    }
}
5
ответ дан 18 December 2019 в 05:21
поделиться

Проблема заключается в бесконечном цикле, а не в уведомлениях "одно за другим".

Если вы хотите, чтобы что-то обновлялось одновременно, вам нужно было запускать это в разных потоках - в этом случае каждый слушатель должен будет синхронизироваться с другими, чтобы получить доступ к объекту, который вызвал событие.

Жаловаться на то, что один бесконечный цикл останавливает выполнение других обновлений, все равно что жаловаться на то, что взял блокировку и затем перешел в бесконечный цикл не позволяет другим получить доступ к заблокированному объекту - проблема в бесконечном цикле, а не в диспетчере блокировок.

20
ответ дан 18 December 2019 в 05:21
поделиться

1. Есть ли способ обойти эту проблему?

Да, убедитесь, что наблюдатель работает нормально и своевременно вернется.

2. Может кто-нибудь объяснить это на примере.

Конечно:

class ObserverImpl implements Observer {
     public void update( Object state ) {
            // remove the infinite loop.
            //while( true ) {
            //   doSomething();
            //}

            // and use some kind of control:
            int iterationControl = 100;
            int currentIteration = 0;
            while( curentIteration++ < iterationControl ) {
                 doSomething();
            }
     }
     private void doSomething(){}
}

Это предотвращает бесконечность данного цикла (если это имеет смысл, он должен выполняться не более 100 раз).

Другой механизм - запустить новая задача во втором потоке, но если она переходит в бесконечный цикл, она в конечном итоге потребляет всю системную память:

class ObserverImpl implements Observer {
     public void update( Object state ) {
         new Thread( new Runnable(){ 
             public void run() {
                 while( true ) {
                     doSomething();
                 }
             }
          }).start();
     }
     private void doSomething(){}
}

Это заставит этот экземпляр наблюдателя немедленно вернуться, но это будет только иллюзией, то, что вам нужно на самом деле нужно избегать бесконечного цикла.

Наконец, если ваши наблюдатели работают нормально, но вы просто хотите уведомить их всех раньше, вы можете взглянуть на этот связанный вопрос: Вызвать код после всех прослушивателей событий мыши выполняются. .

2
ответ дан 18 December 2019 в 05:21
поделиться

I'd be more concerned about the observer throwing an exception than about it looping indefinitely. Your current implementation would not notify the remaining observers in such an event.

3
ответ дан 18 December 2019 в 05:21
поделиться

Все наблюдатели получают уведомление, вот и все гарантия, которую вы получаете.

Если вы хотите реализовать какой-то причудливый порядок, вы можете сделать это:

  • Подключите только одного Наблюдателя;
  • пусть этот основной Наблюдатель уведомит своих друзей в порядке, который вы определяете в коде или с помощью некоторые другие средства.

Это уводит вас от классического паттерна Observer, в котором ваши слушатели жестко запрограммированы, но если это '

0
ответ дан 18 December 2019 в 05:21
поделиться

Это может работать, но я бы сохранил эти изображения в репозитории git, который тогда будет подмодуль репозитория git с исходным кодом.
Таким образом, существует сильная взаимосвязь между кодом и изображениями, даже если изображения находятся в собственном репозитории.
Кроме того, это позволяет избежать проблем, связанных с тем, что git gc или git prune менее эффективны при большом количестве двоичных файлов: если изображения находятся в собственном репозитории, и с несколькими вариациями для каждого из них, обслуживание этого репо довольно невелико. В то время как репозиторий исходного кода может развиваться гораздо более динамично с использованием обычных команд обслуживания git.

так как каждый цикл навсегда будет постоянно поглощать один из потоков из вашего пула.

Лучше всего не позволять им зацикливаться постоянно, или, если они должны, пусть они создают свой собственный поток.

Если вам нужно поддерживать классы, которые не могут измениться, но вы можете определить, какие из них будут выполняться быстро, а какие - «навсегда» (в компьютерных терминах я думаю, что это означает более секунды или двух), тогда вы МОЖЕТЕ использовать такой цикл:

void notify() {
   for (observer: observers) {
      if(willUpdateQuickly(observer))
          observer.update(this);
      else
          new Thread(){
              public static void run() {
                  observer.update(this);
              } 
          }.start();
   }
}

Эй, если он на самом деле "Зацикливается вечно", будет ли он использовать поток для каждого уведомления? Похоже, вам, возможно, придется потратить больше времени на дизайн.

t изменить, но вы можете определить, какой из них будет работать быстро, а какой - «Forever» (в компьютерных терминах я думаю, что это означает более секунды или двух), тогда вы МОЖЕТЕ использовать такой цикл:

void notify() {
   for (observer: observers) {
      if(willUpdateQuickly(observer))
          observer.update(this);
      else
          new Thread(){
              public static void run() {
                  observer.update(this);
              } 
          }.start();
   }
}

Эй, если он на самом деле "циклы вечны", будет ли он потреблять поток для каждого уведомления? Похоже, вам, возможно, придется потратить больше времени на дизайн.

t изменить, но вы можете определить, какой из них будет работать быстро, а какой - «Forever» (в компьютерных терминах я думаю, что это означает более секунды или двух), тогда вы МОЖЕТЕ использовать такой цикл:

void notify() {
   for (observer: observers) {
      if(willUpdateQuickly(observer))
          observer.update(this);
      else
          new Thread(){
              public static void run() {
                  observer.update(this);
              } 
          }.start();
   }
}

Эй, если он на самом деле "циклы вечны", будет ли он потреблять поток для каждого уведомления? Похоже, вам, возможно, придется потратить больше времени на дизайн.

0
ответ дан 18 December 2019 в 05:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: