我有以下问题。给定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次,所以我无法为每个调用启动一个新线程,但整个事情应该在一个线程中。
我希望你能解决问题,有人可以帮助我。
答案 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
。