Java: observer-pattern notify in new thread

I have the following problem. Given the EventNotifier interface for the observer pattern:

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

A class that implements this interface can register in another class, which often calls the newEvent method. The interface is provided by an external library, so I cannot change it. So far I have implemented it with an anonymous class:

 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(); 

For better readability of the code, I would like to open this anonymous class in a new class that extends Thread (because processing should be parallel to other things).

How can I write Thread that does nothing (without an infinite loop, etc.), but wait for the newEvent method to be called? The problem is that newEvent will be called more than 20 times per second, so I cannot start a new thread for every call, but it should all be in the thread.

Hope you have a problem and someone can help me.

+4
source share
3 answers

What makes your message confused is that the EventNotifier is actually an observer / listener (it accepts an event, it does not fire them), and Watcher is actually a notifier (this is an observer, creates an event and calls the newEvent method).

Now I will use the terms observable and observer. Observed fire events, and thus invokes the observer newEvent method.

If you want events to be processed in a separate thread, use BlockingQueue . Run a thread that ends the loop endlessly and tries to take() from the queue at each iteration. Register an observer of the observable who simply accepts the received event and put() it in the lock queue.

+6
source

You can use Executor to avoid BlockingQueue coding and Thread by hand polling.

In your main class, you will have something like:

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

And a parallel event handler that does the processing in the background thread:

 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); } } 

I implemented EventNotifier here, but of course, not necessarily

+2
source

Use plain old wait/notifyAll :

 // we need final object to synchronize your code and library code on it // it 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(); 

For a general introduction to multi-threaded Java programming, read the tutorial . Then, if you are interested in the topic, read Goetz's Java Concurrency in Practice.

In case you need to process the value passed to newEvent from the library, you will need a BlockingQueue instead of a Boolean .

+1
source

Source: https://habr.com/ru/post/1386823/


All Articles