观察者模式和线程

时间:2014-09-19 19:39:32

标签: java multithreading design-patterns

在我们获得触发之前,没有任何建议的副本在SO上回答了我的问题。

尝试这样做:我有一个观察者模式。当我想发送Events时,我希望在Java thread中发送。

问题

  1. 我不想每次都创建一个新线程。我认为这比保持对线程的引用要贵得多。
  2. 我需要将一个Object传递给线程,即Event

    public class EventBus implements Runnable
    {
        private Thread t1;
    
        public EventBus()
        {
            t1 = new Thread(this);
        } 
    
        public void notify(Event event)
        {
            t1.start();
        }
    
        @Override
        public void run()
        {
            for(Listener l : list)
               l.handle(event);
        }
    }
    
  3. 那么如何在不使用类似这样的东西的情况下将我的Event对象传递给run()

    Runnable r = new EventBus(param_value);
    new Thread(r).start();
    

    我知道将参数传递给Thread的方法是将它们放在Thread构造函数中,我不希望这样,我在How can I pass a parameter to a Java Thread?了解到了这一点。

    每次调用Event时,我都需要将新的notify()传递给线程。在执行程序期间notify()将被多次调用,它将携带不同的事件实例。

2 个答案:

答案 0 :(得分:3)

我整理了一个简单的例子,其中sorta显示了我最近如何做异步事件发布。检查一下,我认为它非常自我解释:

主要方法:

public static void main(String[] args) throws InterruptedException {
    Observer obs = new Observer();
    EventBus.subscribe(obs, SomeEventImp.class);

    SomeEventImp evt = new SomeEventImp(new Object(), "This is the value");

    EventBus.publishAsync(evt);

    Thread.sleep(Long.MAX_VALUE);
} 

观察者界面:

public interface IObserver {

    public void update(AEvent event);
}

观察员实施:

public class Observer implements IObserver {
    @Override
    public void update(AEvent event) {
        System.out.println("I got and event from " + event.getSource() + " with a value of " + event.getValue());
    }
}

AEvent课程:

public abstract class AEvent<T> {

    protected final T value;
    protected final Object source;

    public AEvent(Object source, T value) {
        this.value = value;
        this.source = source;
    }

    public Object getSource() {
        return source;
    }

    public T getValue() {
        return value;
    }
}

活动巴士:

public class EventBus {

    // our observers
    private static HashMap<IObserver, Class<?>> m_Observers = new HashMap<IObserver, Class<?>>();
    // our incoming events
    private static BlockingQueue<AEvent<?>> incoming = new LinkedBlockingQueue<AEvent<?>>();

    // start our internal thread
    static {
        new Thread(new DelegationThread()).start();
    }

    // subscribe an observer
    public static void subscribe(IObserver obs, Class<?> evtClass) {
        synchronized (m_Observers) {
            m_Observers.put(obs, evtClass);
        }
    }

    // publish and event
    public static void publishAsync(AEvent<?> event) {
        incoming.add(event);
    }

    private static class DelegationThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    AEvent<?> evnt = incoming.take();
                    synchronized (m_Observers) {
                        for (Entry<IObserver, Class<?>> entry : m_Observers.entrySet()) {
                            if (entry.getValue() == evnt.getClass()) {
                                entry.getKey().update(evnt);
                            }
                        }
                    }
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

最后是事件实现:

public class SomeEventImp extends AEvent<String> {

    public SomeEventImp(Object source, String value) {
        super(source, value);
    }
}

继续输出:

I got and event from java.lang.Object@5e1387c6 with a value of This is the value

显然你会想要清理一下......我只是在几分钟内将它打成一片,并没有真正检查这一切。

答案 1 :(得分:0)

显然你不能使用构造函数参数,因为你不想每次在你想要的计算上启动一个线程时调用构造函数。因此,线程的启动必须与它应该完成的工作区别开来。它必须开始,然后等到计算准备就绪,获取一个对象,告诉它要做什么,然后开始工作。

由于您似乎担心创建新线程,我会假设您需要一个执行一次计算的线程对象,然后让自己准备好另一个,等待它,然后重新开始。我没有看到无限循环的错误。

可能会对上述实现的细节提出其他建议 - 队列,调度程序对象等 - 但这是您实际问题的答案。该线程可以具有由调度程序设置的内部对象,并且调度程序管理队列。随你。它们都是在创建对象后获取某些数据的变体,当然这些对象一直在做。