Java:新线程中的observer-pattern通知

时间:2011-12-17 12:51:09

标签: java multithreading observer-pattern

我有以下问题。给定Observer Pattern的Interface EventNotifier:

public interface EventNotifier {
    void newEvent(final String value);
}

实现此接口的类可以在另一个类中注册,该类经常调用 方法newEvent。接口由外部库提供,因此我无法更改它。到目前为止,我使用匿名类实现了它:

Thread t = new Thread(new Runnable() {

    @Override    
    public void run() {

      watcher = new Watcher(new EventNotifier() {

          @Override
          public void newEvent(String value) {
              //do some stuff
              //will be called more than 20 times per second
          }
       });
 });
 t.start();

为了更好的代码可读性,我想将这个匿名类暴露给一个新类,它扩展了Thread(因为处理应该与其他东西并行)。

如何编写一个Thread,它什么都不做(没有无限循环等),但是等待调用newEvent方法?问题是,newEvent每秒会被调用超过20次,所以我无法为每个调用启动一个新线程,但整个事情应该在一个线程中。

我希望你能解决问题,有人可以帮助我。

3 个答案:

答案 0 :(得分:6)

让你的帖子混淆的是EventNotifier实际上是观察者/听众(它接收事件,它不会触发它们),而Watcher实际上是通知者(它是创建事件并调用newEvent方法的观察者。)

从现在开始,我将使用术语 observable observer 。 observable触发事件,因此调用观察者的newEvent方法。

如果您希望在单独的线程中完成事件处理,请使用BlockingQueue。启动一个无休止循环的线程,并在每次迭代时从队列中尝试take()。将观察者注册到observable,它只接收收到的事件,并在阻塞队列中put()

答案 1 :(得分:2)

您可以使用Executor来避免编码BlockingQueue并手动轮询线程。

在您的主要课程中,您将拥有以下内容:

Executor eventExecutor = Executors.newSingleThreadExecutor();
// ...
watcher = new Watcher(new EventNotifier() {
    public void newEvent(final String value) {
        eventExecutor.execute(new ConcurrentEventHandler(value));
    }   
}); 

在后台线程中执行处理的并发事件处理程序:

class ConcurrentEventHandler implements EventNotifier, Runnable {
        private final String value;

        public ConcurrentEventHandler(String value) {
            this.value = value;
        }

        public void newEvent(final String value) {
            // do some stuff
        }

        public void run() {
            // executed in background thread
            newEvent(value);
        }
    }

我在这里实施了EventNotifier,但当然没有必要

答案 2 :(得分:1)

使用普通的旧wait/notifyAll

// we need final object to synchronize your code and library code on it
// it's convenient to make this object hold all needed data to be passed from library as well
// in your case AtomicBoolean should suffice (we can't use simple `final Boolean`, since it would be impossible to assign new value to it, as we need in code below).

final AtomicBoolean called = new AtomicBoolean(false);

EventNotifier en = new EventNotifier() {
          @Override
          public void newEvent(String value) {
               // this will be called by your external library
               synchronized(called) {
                    called.set(true); called.notifyAll();
               }
          }
       };

Thread t = new Thread(new Runnable() {
    @Override    
    public void run() {
         synchronized(called) {
            // wait here until library call occurs
            while (!called.get()) {
                 try {
                     called.wait();
                 } catch (InterruptedException e) {
                   // handle exception as desired
                 }
            }
            // reset called flag asap, so we will know when next call occurs
            called.set(false);
            ... // do your stuff
         }
    );
 });
t.start();

有关Java多线程编程的一般介绍,请阅读tutorial。然后,如果您对主题感兴趣,请阅读" Java Concurrency in Practice"由Goetz。

如果您需要处理从库中传递到value的{​​{1}},您需要某种newEvent而不是简单的BlockingQueue