2011-12-17 49 views
4

我遇到以下問題。鑑於Observer模式一個接口事件通知:Java:observer-pattern在新線程中通知

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

,A級,將實現該接口,可以在另一個類,它調用經常方法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(因爲處理應平行於其他事情)。如何寫一個線程,它什麼也不做(沒有無盡的循環等),但是等待調用newEvent方法?問題是,newEvent每秒會被調用超過20次,所以我無法爲每個調用啓動一個新線程,但整個事情應該在一個線程中。

我希望你得到這個問題,有人可以幫助我。

+0

在當前設計的T優有線程註冊您的聽衆,然後終止,我覺得這是不是你想要的,不是嗎?你是否想要調用newEvent - 「做一些事情」 - 在單獨的線程中處理?因爲現在它們在運行其他組件的線程中處理。 – 2011-12-17 13:05:30

回答

6

是什麼讓你的帖子感到困惑的是,EventNotifier實際上是一個觀察者/監聽者(它接收事件,它不會觸發它們),而Watcher實際上是通告者(它是創建事件的觀察者並調用newEvent方法)。

從現在起,我將使用術語可觀察的觀察者。可觀察的火災事件,因此調用觀察者的newEvent方法。

如果您希望事件處理在單獨的線程中完成,請使用BlockingQueue。啓動一個無限循環的線程,並在每次迭代時嘗試從隊列中嘗試take()。註冊一個觀察者到observable,它只是將接收的事件和put()它在阻塞隊列中。

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。然後,如果話題對您很有意思,請閱讀Goetz的「Java Concurrency in Practice」。

如果您需要處理value從庫中傳入newEvent,則需要某種BlockingQueue而不是簡單的Boolean

+0

你確定'final Boolean'標誌可以被修改嗎? – 2011-12-17 13:15:12

+0

@DarthBeleg謝謝你,我修復了它 – 2011-12-17 13:16:59

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但它不是」當然必要