Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to monitor Asynchronous requests in Java

Tags:

java

I have 2 classes. One (A) collects some data and the other (B) sends the data to TCP/IP clients. The process is asynchronous with refresh rates from nearly zero to a few seconds. Note that this application has no GUI so I won't be able to use many built in "onChange" listeners.

In normal conditions I would simply write the code so that A calls a "send" method on B, passing the data, no problems here.

Now, assume that the rate A collects data is critical (real time) and that A cannot wait for B to complete the sending process (note that B uses TCP, not UDP). The way I implemented this is

  • A places the data in a field in B
  • B has a continuous loop that checks if the data is new or now. If new, it will send it out.

If during the send the data is updated a few times it doesn't matter, as long as it doesn't slow down A. Spawning a new thread for each send would in principle not slow down A but it's likely gonna result in a mess.

You can see that B is working in synchronous mode (but A isn't) and it's implemented with a while loop with a Thread.sleep() call. My questions are:

  1. Should I use a timer task instead of the while loop? I know that most people hate the Thread.sleep() call but ultimately the only thing I'm interested is in keeping CPU low.

  2. Isn't there a more elegant way than the synchronous approach? In some cases the data refresh of A is about 1 second and it would be nice if I could just have a listener that would act on an event. In such case a sleep time of 25ms would be a waste of cycles. In other cases it's very fast and I'd like no sleep at all.

*Example: imagine that A is submitting screenshots from your screen and B is sending them to the clients. Only the last one matters and B is gonna go as fast as possible *

Any ideas or suggestions? Please keep things as simple and low cpu as possible

thanks a lot!

like image 833
Lele Avatar asked Sep 16 '12 14:09

Lele


2 Answers

I would make it like this:

A collects the data in whatever fashion is appropriate and then post the "next message" to send. If there is already a message pending, let the new message replace / update the previous.

B checks for ay pending messages, if one is available it grabs it and send it to the client(s). However, if no message is pending, then B waits for one to be available.

Object lock = new Object();
Object pending = null;

public void post(Object message) {
    synchronized (lock) {
        pending = message;
        lock.notifyAll();
    }
}

public Object getNextMessage() {
    Object message;
    synchronized (lock) {
        while (pending == null) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                // Ignore
            }
        }
        message = pending;
        pending = null;
    }
    return message;
}

Using a queue you could instead do

BlockingDeque<Object> queue = new LinkedBlockingDeque<Object>(1);

public void postMessage(Object message) {
    // If previous message is still pending we replace it.
    queue.clear();
    queue.offer(message);
}

public Object getNextMessage() {
    while (true) {
        try {
            return queue.take();
        } catch (InterruptedException e) {
            // Ignore interrupts
        }
    }
}

Of course in both example it would be good to instead of the while (true) use a signal so you can gracefully shut down.

like image 117
Roger Lindsjö Avatar answered Oct 16 '22 02:10

Roger Lindsjö


I would set up a LinkedBlockingQueue between A and B whose size should not block A when the queue becomes full. In A, the method that collects the data will post it to the queue. In B, as long as there is an item in the queue, it is new and should be sent out.

If you want B to take advantage of multiple edits to a message by A to be merged and sent out as a single update, then I would do it using the Observer.

  1. The message that A keeps updating is the Observable.
  2. B is an observer of this message.
  3. Every time A updates the message, it is an indication for B to take some action.
  4. B can choose to send the update to the clients immediately
  5. B can also choose to wait for a certain period of time using a Timer and send the update to clients only after the timer fires off. The code to send update will be the TimerTask.
  6. B would not set the Timer again until A changes the message.
like image 22
Vikdor Avatar answered Oct 16 '22 01:10

Vikdor